cyborg-hunter 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/CITATION.cff +2 -2
- package/README.md +5 -3
- package/dist/cyborg-hunter-replay.js +2 -2
- package/dist/cyborg-hunter.esm.js +1 -1
- package/dist/cyborg-hunter.min.js +2 -2
- package/dist/extension-cyborg-hunter.js +1 -1
- package/package.json +1 -1
- package/src/cli/preview-entry.js +6 -0
- package/src/cli/renderers/font-face-css.js +16 -0
- package/src/cli/renderers/fonts/FONTS_MANIFEST.json +69 -0
- package/src/cli/renderers/fonts/majormonodisplay/OFL.txt +93 -0
- package/src/cli/renderers/fonts/majormonodisplay/majormonodisplay-400.woff2 +0 -0
- package/src/cli/renderers/fonts/recursive/OFL.txt +93 -0
- package/src/cli/renderers/fonts/recursive/recursive-300-1000.woff2 +0 -0
- package/src/cli/renderers/fonts/sofiasans/OFL.txt +93 -0
- package/src/cli/renderers/fonts/sofiasans/sofiasans-1-1000.woff2 +0 -0
- package/src/cli/renderers/fonts/sora/OFL.txt +93 -0
- package/src/cli/renderers/fonts/sora/sora-100-800.woff2 +0 -0
- package/src/cli/renderers/fonts/spacegrotesk/OFL.txt +93 -0
- package/src/cli/renderers/fonts/spacegrotesk/spacegrotesk-300-700.woff2 +0 -0
- package/src/cli/renderers/fonts/tomorrow/OFL.txt +93 -0
- package/src/cli/renderers/fonts/tomorrow/tomorrow-400.woff2 +0 -0
- package/src/cli/renderers/html-index-core.js +98 -96
- package/src/cli/renderers/html-index.js +7 -2
- package/src/cli/renderers/replay-styles.js +61 -0
- package/src/cli/renderers/replay-viewer.client.js +8 -6
- package/src/cli/renderers/report-fonts.js +24 -0
- package/src/jspsych/extension-cyborg-hunter-replay.js +1 -1
- package/src/jspsych/extension-cyborg-hunter.js +1 -1
- package/src/shared/constants.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,31 @@
|
|
|
3
3
|
All notable changes to **cyborg-hunter** are documented here. This project follows
|
|
4
4
|
[Semantic Versioning](https://semver.org).
|
|
5
5
|
|
|
6
|
+
## [0.9.1] — 2026-10-01
|
|
7
|
+
|
|
8
|
+
A visual redesign of the HTML triage report and the live demo. No change to
|
|
9
|
+
scoring, data formats or the browser library's behaviour.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Report typefaces: six Google Fonts families (Space Grotesk, Tomorrow, Sofia
|
|
13
|
+
Sans, Sora, Recursive, Major Mono Display) are embedded in every
|
|
14
|
+
`index.html` as base64 WOFF2 (about +227 KB), so the report stays a single
|
|
15
|
+
offline file. Each text role uses one of them; their OFL licences ship in
|
|
16
|
+
`src/cli/renderers/fonts/`.
|
|
17
|
+
- Report shapes: high-contrast neutrals, square badges, tiles and boxes, a
|
|
18
|
+
double rule under the header, soft shadows on cells and plots, an outlined
|
|
19
|
+
selected participant row, the filter chips as one segmented control, hairline
|
|
20
|
+
boxes for the triage note and paste evidence, a round ink play button in the
|
|
21
|
+
replay viewer, and larger keycast chips.
|
|
22
|
+
- Replay viewer: the cursor trail is drawn as fading breadcrumb dots instead of
|
|
23
|
+
a line.
|
|
24
|
+
- Live demo: restyled in the same aesthetic (fonts, neutrals, segmented tabs,
|
|
25
|
+
square cards). The report and replay viewer embedded in the demo now get the
|
|
26
|
+
report's fonts and the CLI's own replay CSS, replacing a hand-kept copy that
|
|
27
|
+
had drifted.
|
|
28
|
+
- `.mono` in the report now defaults to Sora with tabular figures; form
|
|
29
|
+
controls no longer fall back to the browser's default font.
|
|
30
|
+
|
|
6
31
|
## [0.9.0] — 2026-09-29
|
|
7
32
|
|
|
8
33
|
The report's triage-score weights are configurable from the CLI config. Default
|
package/CITATION.cff
CHANGED
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ Browser (experiment page) — load via unpkg or copy `dist/*.js` into your proje
|
|
|
53
53
|
<script src="https://unpkg.com/cyborg-hunter/dist/cyborg-hunter-replay.js"></script>
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
For production studies, pin a version: `https://unpkg.com/cyborg-hunter@0.9.
|
|
56
|
+
For production studies, pin a version: `https://unpkg.com/cyborg-hunter@0.9.1/dist/...`.
|
|
57
57
|
|
|
58
58
|
## Plug into a jsPsych experiment
|
|
59
59
|
|
|
@@ -204,7 +204,7 @@ Run the test suite with `npm test`. Before publishing, run `scripts/check-public
|
|
|
204
204
|
author = {Konuk, Can and Btesh, Victor and Nunez, Jose Luis},
|
|
205
205
|
title = {cyborg-hunter: detecting AI-tool use in browser-based behavioral experiments},
|
|
206
206
|
year = {2026},
|
|
207
|
-
version = {0.9.
|
|
207
|
+
version = {0.9.1},
|
|
208
208
|
url = {https://github.com/cyborg-hunter/cyborg-hunter},
|
|
209
209
|
license = {MIT}
|
|
210
210
|
}
|
|
@@ -214,4 +214,6 @@ A "Cite this repository" button is rendered from `CITATION.cff`.
|
|
|
214
214
|
|
|
215
215
|
## License
|
|
216
216
|
|
|
217
|
-
MIT
|
|
217
|
+
MIT. The HTML report embeds six typefaces from Google Fonts (Space Grotesk,
|
|
218
|
+
Tomorrow, Sofia Sans, Sora, Recursive, Major Mono Display), each under the SIL
|
|
219
|
+
Open Font License 1.1; their licences ship in `src/cli/renderers/fonts/`.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
// cyborg-hunter-replay v0.9.
|
|
1
|
+
// cyborg-hunter-replay v0.9.1 — https://github.com/cyborg-hunter/cyborg-hunter
|
|
2
2
|
(()=>{var Tt=1,De=new WeakSet,Ve=0;function ge(e){return e&&typeof e.has=="function"?e:De}function D(e,r){if(e){var t=ge(r);t===De&&Ve++,t.add(e)}return e}function ze(){return Ve>0}function W(e,r){return!!e&&ge(r).has(e)}function ie(e,r){for(var t=ge(r),n=e;n;){if(t.has(n))return!0;n=n.parentNode}return!1}function Et(e){for(var r=e.attributes||[],t=0;t<r.length;t++)if(r[t].name==="type")return r[t].value==="password";return!1}function Rt(e){return!e||e.tagName!=="INPUT"?!1:e.type==="password"||Et(e)}function q(e,r){if(Rt(e))return!0;if(!r||!e||typeof e.matches!="function")return!1;try{return e.matches(r)}catch{return!1}}function U(e,r){for(var t=e;t;){if(t.nodeType===Tt&&q(t,r))return!0;t=t.parentNode}return!1}var He={participantId:"unknown",tier:"trace",keys:"full",mouseHz:30,redactSelector:"[data-ch-redact]",keepBait:!1,clipboardContent:!1,root:null,keyframeEvery:10,autoSave:{mode:"none"},maxEventsPerTrial:5e4,maxCharsPerTrial:8e6,maxViewportChanges:2e3,maxGuardViolations:40},Ct={created:["session","destroyed"],session:["trial","stopped","destroyed"],trial:["session","stopped","destroyed"],stopped:["destroyed"],destroyed:[]};function je(e){var r=Object.assign({},He,e||{});r.autoSave=Object.assign({},He.autoSave,(e||{}).autoSave||{});var t="created",n=[],a=[],i=[];function u(){var l=i;i=[];for(var p=0;p<l.length;p++)try{l[p]()}catch(w){b.captureFailure("pre_close_flush",w)}}var s=0,d=[],g=new WeakMap,S=new WeakSet;function x(l){try{return JSON.stringify(l).length}catch{return 0}}var m={participantId:r.participantId,tier:r.tier,keys:r.keys,sessionStart:null,sessionStartEpoch:null,userAgent:"",viewport:null,viewportClient:null,observedRoot:null,inheritedRedactionTaint:!1,stylesheets:[],trials:[],guardViolations:[],viewportChanges:[],captureFailures:[],captureStopped:!1,endReason:null},y=null;function R(l){if(Ct[t].indexOf(l)===-1)throw new Error("[cyborg-hunter-replay] invalid lifecycle call: "+t+" \u2192 "+l+". Expected order: attach() \u2192 startSession() \u2192 (startTrial \u2192 endTrial)* \u2192 stopSession() \u2192 destroy()."+(t==="created"?" Did you forget startSession()?":""));t=l}function E(l,p){return s++,{trialIndex:s-1,trialId:l&&l.trialId||(p?"__session__":"trial-"+(s-1)),plugin:l&&l.plugin||"ch:standalone",implicit:!!p,tLoad:p&&s===1?m.sessionStart:performance.now(),tStart:(l&&l.tStart)!=null?l.tStart:null,tDomReady:(l&&l.tDomReady)!=null?l.tDomReady:null,tEnd:null,initialDom:null,initialState:null,events:[]}}function O(){y.tEnd=performance.now(),m.trials.push(y),y=null}function B(l){for(var p=0;p<d.length;p++)try{d[p](l)}catch(w){m.captureFailures.push({channel:"trial_start_hook",message:w&&w.message?String(w.message):String(w),t:performance.now()})}}var A=!1,M=!1;function V(l,p){var w=0;for(var I in p)if(!(I==="t"||!Object.prototype.hasOwnProperty.call(p,I))){if(l[I]!==p[I])return!1;w++}for(var te in l)te==="t"||!Object.prototype.hasOwnProperty.call(l,te)||w--;return w===0}var P=!1;function k(l,p,w){S.add(l),m.captureStopped=!0,!P&&(P=!0,l.events.push({type:"recording.capture_stopped",t:p,reason:"buffer_limit",extensions:{"cyborg-hunter":w}}))}function v(l){if(t==="destroyed")throw new Error("[cyborg-hunter-replay] event pushed to a destroyed recorder");if(!(t==="created"||t==="stopped")&&(y||(y=E(null,!0),B(y)),!S.has(y))){if(y.events.length>=r.maxEventsPerTrial){k(y,l.t,{limit_events:r.maxEventsPerTrial});return}if(r.maxCharsPerTrial!=null){var p=g.get(y)||0;if(p+=x(l),p>r.maxCharsPerTrial){k(y,l.t,{limit_chars:r.maxCharsPerTrial});return}g.set(y,p)}y.events.push(l)}}var b={config:r,startSession:function(){R("session"),m.sessionStart=performance.now(),m.sessionStartEpoch=Date.now(),m.inheritedRedactionTaint=ze();var l=typeof window<"u"?window:null,p=l&&l.visualViewport?l.visualViewport:null;m.viewport=l?{w:l.innerWidth||0,h:l.innerHeight||0,dpr:l.devicePixelRatio||1,scale:p&&typeof p.scale=="number"?p.scale:1,offset_x:p&&p.offsetLeft||0,offset_y:p&&p.offsetTop||0}:null;var w=typeof document<"u"&&document.documentElement?document.documentElement:null;m.viewportClient=w?{w:w.clientWidth||0,h:w.clientHeight||0}:null,m.userAgent=typeof navigator<"u"&&navigator.userAgent?String(navigator.userAgent):"",r.autoSave.mode==="none"&&console.warn('[cyborg-hunter-replay] autoSave.mode is "none" \u2014 the recording will be lost unless you call getRecording() yourself.')},startTrial:function(l){t==="trial"?(this.captureFailure("lifecycle",new Error("startTrial_without_endTrial: the open trial was auto-closed")),O(),t="session"):y&&O(),R("trial"),y=E(l,!1),B(y)},endTrial:function(){R("session"),y&&O()},stopSession:function(l){u(),t==="trial"&&(t="session"),y&&O(),R("stopped"),m.endReason=l||"finished"},pushRecord:function(l,p){var w=Object.assign({type:l.type,t:null},l);w.t=p??performance.now(),v(w)},pushViewportChange:function(l,p){if(t==="destroyed")throw new Error("[cyborg-hunter-replay] viewport change pushed to a destroyed recorder");if(!(t==="created"||t==="stopped")){var w=m.viewportChanges;if(!(w.length&&V(w[w.length-1],l))){var I=r.maxViewportChanges;if(I!=null&&w.length>=I){A||(A=!0,b.captureFailure("viewport_changes",new Error("viewport_changes cap reached ("+I+"); later viewport geometry is not recorded")));return}w.push(Object.assign({},l,{t:p??performance.now()}))}}},pushGuardViolation:function(l,p){if(t==="destroyed")throw new Error("[cyborg-hunter-replay] guard violation pushed to a destroyed recorder");if(!(t==="created"||t==="stopped")){var w=r.maxGuardViolations;if(w!=null&&m.guardViolations.length>=w){M||(M=!0,b.captureFailure("guard_violations",new Error("guard_violations cap reached ("+w+"); later guard violations are not recorded")));return}m.guardViolations.push(Object.assign({},l,{t:p??performance.now()}))}},noteSnapshotChars:function(l,p){l&&typeof p=="number"&&isFinite(p)&&g.set(l,p)},captureFailure:function(l,p){m.captureFailures.push({channel:l,message:p&&p.message?String(p.message):String(p),t:performance.now()})},onTrialStart:function(l){d.push(l)},setStylesheets:function(l){m.stylesheets=l||[]},setObservedRoot:function(l){m.observedRoot=typeof l=="string"&&l?l:null},addListener:function(l,p,w,I){l.addEventListener(p,w,I||!1),n.push({target:l,event:p,handler:w,options:I||!1})},addInterval:function(l){a.push(l)},addPreCloseFlush:function(l){typeof l=="function"&&i.push(l)},getState:function(){var l=m.trials.slice();return y&&l.push(y),Object.assign({},m,{trials:l,state:t})},destroy:function(){t!=="destroyed"&&(u(),R("destroyed"),n.forEach(function(l){l.options&&l.options._isObserver?l.handler.disconnect():l.target.removeEventListener(l.event,l.handler,l.options)}),n=[],a.forEach(function(l){clearInterval(l)}),a=[])}};return b}var Se=1,we=3,Be=8,It={SCRIPT:!0,NOSCRIPT:!0},kt={VIDEO:!0,AUDIO:!0},Nt="data-record-exclude",Pt={"data-ch-role":!0,"data-ch-decoy":!0},At="ch-decoy",Ot="data-ch-shadow",Mt=/^[a-zA-Z_:][-a-zA-Z0-9_:.]*$/;function Lt(e){return Mt.test(e)&&!/^on/i.test(e)}function oe(e,r){for(var t=e.attributes||[],n=0;n<t.length;n++)if(t[n].name===r)return t[n].value;return null}function F(e,r){if(!e||e.nodeType!==Se)return!1;for(var t=e.attributes||[],n=!1,a=0;a<t.length;a++){var i=t[a].name;if(i===Nt)return!0;Pt[i]&&(n=!0)}return r&&r.keepBait?!1:n||e.id===At}function Ft(e){var r=Ge(e.width,oe(e,"width")),t=Ge(e.height,oe(e,"height"));return r===null||t===null?null:{w:r,h:t}}function Ge(e,r){if(typeof e=="number"&&isFinite(e))return e;var t=parseInt(r,10);return isFinite(t)?t:null}function Dt(e){var r=e.currentSrc||e.src||oe(e,"src");return typeof r=="string"&&r?r:null}function We(e,r,t){return!(!Lt(r)||r==="srcdoc"&&e==="IFRAME"||r==="value"&&t)}function Ue(e,r,t,n){return t==="src"&&r==="IMG"&&typeof e.src=="string"&&e.src?e.src:String(n)}function Ke(e,r,t){for(var n={},a=!1,i=e.attributes||[],u=0;u<i.length;u++){var s=i[u].name;We(r,s,t)&&(n[s]=Ue(e,r,s,i[u].value),s==="src"&&(a=!0))}return!a&&r==="IMG"&&typeof e.src=="string"&&e.src&&(n.src=e.src),e.shadowRoot&&(n[Ot]=""),n}var ue={withheld:!0};function be(e,r,t){var n=e.tagName||"";if(!We(n,r,t))return ue;var a=oe(e,r);return a===null?null:Ue(e,n,r,a)}function _e(e,r){return Ke(e,e.tagName||"",r)}function Q(e){if(!e)return!1;var r=e.nodeType;return r===we||r===Be?!0:r!==Se?!1:!It[e.tagName||""]}function Z(e,r){return!e||e.nodeType!==Se||r?!1:(e.tagName||"")!=="IFRAME"}function $(e,r,t,n){if(!e||!r)return null;t=t||{};for(var a=[],i=e;i&&i!==r;){a.push(i);var u=i.parentNode;!u&&a.length===1&&n&&(u=n),i=u}if(i!==r||!Q(r))return null;for(var s=r,d=a.length-1;d>=0;d--){if(!Z(s,F(s,t))||!Q(a[d]))return s;s=a[d]}return s}function Xe(e,r,t,n,a){if(!Q(e))return null;var i=e.nodeType;if(r.delivery.deliver(e,a||null),!n&&W(e,t.taint)&&(n=!0),i===we||i===Be)return n&&D(e,t.taint),{id:r.registry.idFor(e),kind:i===we?"text":"comment",text:n?"":String(e.textContent||"")};var u=e.tagName||"",s=r.registry.idFor(e);if(F(e,t))return{id:s,kind:"element",tag:u.toLowerCase()};var d=n||q(e,t.redactSelector);d&&D(e,t.taint);var g={id:s,kind:"element",tag:u.toLowerCase(),attrs:Ke(e,u,d),children:[]},S=u==="CANVAS"?Ft(e):null;S&&(g.canvas_size=S);var x=kt[u]&&!d?Dt(e):null;if(x&&(g.media_src=x),!Z(e,!1))return g;for(var m=e.childNodes||[],y=0;y<m.length;y++){var R=Xe(m[y],r,t,d,e);R&&g.children.push(R)}return g}function K(e,r,t){return t=t||{},e?(r.registry.assignTree(e),Xe(e,r,t,U(e,t.redactSelector)||ie(e,t.taint),e.parentNode||null)):null}var Vt=1;function T(e,r,t){return function(n){try{t(n)}catch(a){e.captureFailure(r,a)}}}function j(e){return Math.round(e*10)/10}function N(e){return typeof e=="number"&&isFinite(e)?Math.round(e):0}function Ye(e){return e==null?"":String(e)}var Je="cyborg-hunter";function qe(e,r){var t=e.extensions||(e.extensions={});return t[Je]=Object.assign({},t[Je],r),e}function Qe(e,r){r=r||{};var t=r.doc||document,n=r.win||window,a=r.now||function(){return performance.now()},i=r.raf||(typeof requestAnimationFrame<"u"?requestAnimationFrame.bind(null):function(o){setTimeout(o,16)}),u=e.config,s=r.span||null,d={keepBait:u.keepBait,redactSelector:u.redactSelector,taint:r.taint};function g(o){try{if(!o||typeof o.composedPath!="function")return null;var f=o.composedPath()[0];return f&&f!==o.target?f:null}catch{return null}}function S(o){return x(o,!0).node}function x(o,f){var c={redacted:!1,excluded:!1,node:null,heldEl:null};if(!o)return c;for(var h=!1,_=!1,L=!f||!s,C=o;C&&!(h&&_&&L);){if(!h&&W(C,d.taint)&&(h=!0),!h&&C.nodeType===Vt&&q(C,d.redactSelector)&&(h=!0),!_&&F(C,d)&&(_=!0),!L&&s.delivery.holds(C)){var J=s.registry.peekId(C);c.node=J??null,c.heldEl=C,L=!0}C=C.parentNode}return h&&D(o,d.taint),c.redacted=h,c.excluded=_,c}function m(o){var f=o&&o.target,c=g(o),h=x(f,!0),_=h.redacted,L=h.excluded;if(c){var C=x(c,!1);C.redacted&&(_=!0),C.excluded&&(L=!0)}return{el:f,composed:c,redacted:_,excluded:L,node:h.node,heldEl:h.heldEl}}function y(){var o=t.documentElement;return{cw:o&&o.clientWidth?o.clientWidth:n.innerWidth,ch:o&&o.clientHeight?o.clientHeight:n.innerHeight}}function R(o){return N(o&&o.clientX)}function E(o){return N(o&&o.clientY)}function O(){var o=y(),f=n.visualViewport;return{scroll_x:N(n.scrollX),scroll_y:N(n.scrollY),viewport_w:N(n.innerWidth),viewport_h:N(n.innerHeight),client_w:N(o.cw),client_h:N(o.ch),dpr:typeof n.devicePixelRatio=="number"?n.devicePixelRatio:1,vv_scale:f&&typeof f.scale=="number"?f.scale:1,vv_offset_x:f?j(f.offsetLeft||0):0,vv_offset_y:f?j(f.offsetTop||0):0}}function B(o){var f=o.el;if(!f||!f.tagName||o.excluded&&!o.heldEl)return null;var c=o.excluded&&o.heldEl&&o.heldEl!==f?o.heldEl:f,h={tag:(c.tagName||"").toLowerCase()};!o.redacted&&!o.excluded&&(h.id=c.id||null);try{if(typeof c.getBoundingClientRect=="function"){var _=c.getBoundingClientRect();h.rect={x:j(_.left),y:j(_.top),w:j(_.width),h:j(_.height)}}}catch{}return h.node=o.node,h}function A(o,f){return f.composed&&qe(o,{shadow_retarget:!0}),o}var M=null,V=new Map,P=null,k=null,v=!1,b=!1,l=!1;function p(){v=!1,M&&(e.pushRecord({type:"scroll.window",x:N(n.scrollX),y:N(n.scrollY)},M.t),M=null),V.size>0&&(V.forEach(function(o,f){var c=x(f,!0);if(!c.excluded){var h=c.node;h!=null&&e.pushRecord({type:"scroll.element",node:h,x:N(f.scrollLeft),y:N(f.scrollTop)},o.t)}}),V.clear())}function w(){var o=n.visualViewport;return{w:N(n.innerWidth),h:N(n.innerHeight),dpr:typeof n.devicePixelRatio=="number"?n.devicePixelRatio:1,scale:o&&typeof o.scale=="number"?o.scale:1,offset_x:o?j(o.offsetLeft||0):0,offset_y:o?j(o.offsetTop||0):0}}function I(){P&&(e.pushViewportChange(w(),P.t),P=null)}function te(){k&&(e.pushViewportChange(w(),k.t),k=null)}function ce(){if(b=!1,l=!1,P&&k){var o=Math.max(P.t,k.t);P=null,k=null,e.pushViewportChange(w(),o);return}I(),te()}function H(){p(),ce()}function re(o,f){o.camera=O();var c=B(f);return c&&(o.anchor=c),o}var wt=1e3/(u.mouseHz||30),Ae=-1/0;e.addListener(t,"mousemove",T(e,"mouse",function(o){var f=a();f-Ae<wt||(Ae=f,e.pushRecord({type:"mouse.move",x:R(o),y:E(o)},f))}),{passive:!0,capture:!0}),[["mousedown","mouse.down"],["mouseup","mouse.up"],["click","mouse.click"]].forEach(function(o){e.addListener(t,o[0],T(e,"mouse",function(f){H();var c=m(f),h=re({type:o[1],x:R(f),y:E(f),button:typeof f.button=="number"?f.button:0,target:c.node},c);e.pushRecord(A(h,c),a())}),{passive:!0,capture:!0})}),u.keys!=="off"&&[["keydown","key.down"],["keyup","key.up"]].forEach(function(o){e.addListener(t,o[0],T(e,"keys",function(f){var c=m(f);if(c.redacted||c.excluded){e.pushRecord(A({type:o[1],redacted:!0},c),a());return}var h=o[1]==="key.down"&&!f.repeat;h&&H();var _={type:o[1],key:Ye(f.key),code:Ye(f.code),mods:{ctrl:!!f.ctrlKey,shift:!!f.shiftKey,alt:!!f.altKey,meta:!!f.metaKey},repeat:!!f.repeat,target:c.node};h&&re(_,c),e.pushRecord(A(_,c),a())}),!0)});function Oe(o){var f=null,c=null;try{f=o("text")}catch{}if(u.clipboardContent)try{c=o("text/html")||null}catch{}return{text:typeof f=="string"?f:null,html:c}}function ne(o,f,c){var h={type:o,target:f.node,text:null,html:null,len:c&&c.text!=null?c.text.length:null};return f.redacted&&(h.redacted=!0),f.excluded&&(h.len=null),u.clipboardContent&&!f.redacted&&!f.excluded&&c&&(h.text=c.text,h.html=c.html,h.len=null),A(h,f)}e.addListener(t,"paste",T(e,"clipboard",function(o){H();var f=m(o),c=o.clipboardData,h=Oe(function(_){return c.getData(_)});e.pushRecord(ne("clipboard.paste",f,h),a())}),!0),e.addListener(t,"copy",T(e,"clipboard",function(o){H(),e.pushRecord(ne("clipboard.copy",m(o),null),a())}),!0),e.addListener(t,"cut",T(e,"clipboard",function(o){H(),e.pushRecord(ne("clipboard.cut",m(o),null),a())}),!0),e.addListener(t,"drop",T(e,"clipboard",function(o){H();var f=m(o),c=o.dataTransfer,h=Oe(function(_){return c.getData(_)});e.pushRecord(ne("clipboard.drop",f,h),a())}),!0);var pe=new Map,he=!1;function St(o){return o.value!=null?String(o.value):o.isContentEditable&&o.textContent!=null?String(o.textContent):""}function bt(o){for(var f=[],c=o.options||[],h=0;h<c.length;h++)c[h].selected&&f.push(typeof c[h].value=="string"?c[h].value:String(c[h].textContent||""));return f}function Me(o){if(!o||o.tagName!=="INPUT")return!1;if(String(o.type||"").toLowerCase()==="file")return!0;var f=typeof o.getAttribute=="function"?o.getAttribute("type"):null;return typeof f=="string"&&f.toLowerCase()==="file"}function _t(o,f){var c=x(o,!0);if(c.excluded)return null;var h=f?x(f,!1):null;if(h&&h.excluded)return null;var _=c.node;if(_==null)return null;var L=c.redacted||!!(h&&h.redacted);if(Me(o)||f&&Me(f))return null;var C=String(o.type||"").toLowerCase();if(o.tagName==="SELECT")return L?null:{type:"input.select",node:_,values:bt(o)};if(o.tagName==="INPUT"&&(C==="checkbox"||C==="radio"))return L?null:{type:"input.checked",node:_,checked:!!o.checked};var J=St(o);return L?{type:"input.value",node:_,redacted:!0,value_len:J.length}:{type:"input.value",node:_,value:J}}function xt(){he=!1,pe.forEach(function(o,f){var c=_t(f,o.composed);c&&(o.composed&&qe(c,{shadow_retarget:!0}),e.pushRecord(c,o.t))}),pe.clear()}e.addListener(t,"input",T(e,"input",function(o){o.target&&(pe.set(o.target,{t:a(),composed:g(o)}),he||(he=!0,i(T(e,"input",xt))))}),!0);var ae=new Set;function Le(){ae.forEach(function(o){o&&o.isConnected===!1&&ae.delete(o)})}e.addListener(n,"scroll",T(e,"scroll",function(o){var f=o&&o.target&&o.target.tagName?o.target:null;f?(V.set(f,{t:a()}),ae.add(f)):M={t:a()},v||(v=!0,i(T(e,"scroll",p)))}),{passive:!0,capture:!0});function ve(o){for(var f=[],c=0;c<(o?o.length:0);c++){var h=o[c];f.push({id:typeof h.identifier=="number"?h.identifier:c,x:R(h),y:E(h)})}return f}e.addListener(t,"touchstart",T(e,"touch",function(o){H();var f=m(o),c=re({type:"touch.start",touches:ve(o.touches)},f);e.pushRecord(A(c,f),a())}),{passive:!0,capture:!0});var me=!1,ye=null,Fe=0;return e.addListener(t,"touchmove",T(e,"touch",function(o){ye=ve(o.touches),Fe=a(),!me&&(me=!0,i(T(e,"touch",function(){me=!1,ye&&e.pushRecord({type:"touch.move",touches:ye},Fe)})))}),{passive:!0,capture:!0}),e.addListener(t,"touchend",T(e,"touch",function(o){H();var f=m(o),c=re({type:"touch.end",touches:ve(o.changedTouches)},f);e.pushRecord(A(c,f),a())}),{passive:!0,capture:!0}),e.addListener(n,"blur",T(e,"focus",function(){e.pushRecord({type:"blur"},a())})),e.addListener(n,"focus",T(e,"focus",function(){e.pushRecord({type:"focus"},a())})),e.addListener(t,"visibilitychange",T(e,"focus",function(){e.pushRecord({type:t.hidden?"visibility.hidden":"visibility.visible"},a())})),e.addListener(n,"resize",T(e,"viewport",function(){P={t:a()},b||(b=!0,i(T(e,"viewport",ce)))})),n.visualViewport&&typeof n.visualViewport.addEventListener=="function"&&["resize","scroll"].forEach(function(o){e.addListener(n.visualViewport,o,T(e,"viewport",function(){k={t:a()},l||(l=!0,i(T(e,"viewport",ce)))}))}),e.onTrialStart(function(){Le()}),{getScrolledElements:function(){return Le(),ae}}}var xe=1,Ze={childList:!0,attributes:!0,attributeOldValue:!0,characterData:!0,subtree:!0};function $e(e,r){var t=[];if(!e||!e.length||!r||!r.root||!r.span)return t;var n={out:t,root:r.root,span:r.span,registry:r.span.registry,delivery:r.span.delivery,t:r.t,opts:r,pending:new Map,pendingAdd:new Map,attrs:new Map,attrOrder:[],transitioned:new Set,restored:new Set,payloads:new Set,noHeldFrom:new Map};zt(e,n),jt(n);for(var a=0;a<e.length;a++){var i=e[a];i&&(i.type==="childList"?Gt(i,n):i.type==="attributes"?Xt(i,n):i.type==="characterData"&&Qt(i,n))}return t}function zt(e,r){for(var t=0;t<e.length;t++){var n=e[t];if(n){if(n.type==="childList"){for(var a=n.removedNodes||[],i=0;i<a.length;i++)r.pending.set(a[i],(r.pending.get(a[i])||0)+1);for(var u=n.addedNodes||[],s=0;s<u.length;s++)r.pendingAdd.set(u[s],(r.pendingAdd.get(u[s])||0)+1)}else if(n.type==="attributes"&&n.target&&n.attributeName){var d=r.attrs.get(n.target);d||(d=new Map,r.attrs.set(n.target,d),r.attrOrder.push(n.target));var g=it(n.target,n)||n.attributeName,S=d.get(g);S?S.count++:d.set(g,{first:n.oldValue,count:1})}}}}function se(e,r,t){var n=t.attrs.get(e),a=n&&n.get(r),i=et(e,r);return a?a.count===1&&i===null?a.first==null?"":a.first:a.first==null?null:a.first:i}function et(e,r){for(var t=e.attributes||[],n=0;n<t.length;n++)if(t[n].name===r)return t[n].value;return null}function Ht(e,r){var t=se(e,"id",r);return F({nodeType:xe,id:t??"",attributes:tt(e,r)},r.opts)}function tt(e,r){for(var t=[],n={},a=e.attributes||[],i=0;i<a.length;i++){var u=a[i].name;n[u]=!0;var s=se(e,u,r);s!==null&&t.push({name:u,value:s})}var d=r.attrs.get(e);return d&&d.forEach(function(g,S){if(!n[S]){var x=se(e,S,r);x!==null&&t.push({name:S,value:x})}}),t}function jt(e){for(var r=new Map,t=0;t<e.attrOrder.length;t++){var n=e.attrOrder[t];if(!(!n||n.nodeType!==xe)&&e.delivery.holds(n)){var a=e.registry.peekId(n);a!=null&&Ht(n,e)!==F(n,e.opts)&&r.set(n,a)}}var i=new Set;r.forEach(function(u,s){rt(s,r,i,e)})}function rt(e,r,t,n){if(!t.has(e)){t.add(e);for(var a=[],i=e.parentNode;i&&(r.has(i)&&a.push(i),i!==n.root);i=i.parentNode);for(var u=a.length-1;u>=0;u--)rt(a[u],r,t,n);n.transitioned.add(e),n.delivery.holds(e)&&(Yt(e,n)||(F(e,n.opts)?Jt(e,r.get(e),n):qt(e,r.get(e),n)))}}function Gt(e,r){for(var t=e.removedNodes||[],n=0;n<t.length;n++)Bt(t[n],e.target,r);for(var a=e.addedNodes||[],i=0;i<a.length;i++)Wt(a[i],e.target,r)}function Bt(e,r,t){if(at(t.pending,e),!nt(e,t)){var n=t.delivery;if(!(!n.holds(e)||n.parentOf(e)!==r)&&$(r,t.root,t.opts)===r){var a=t.registry.peekId(e);a!=null&&(t.out.push({type:"dom.remove",t:t.t,node:a}),n.purge(e))}}}function nt(e,r){for(var t=e&&e.parentNode;t;t=t.parentNode){if(r.payloads.has(t))return!0;if(t===r.root)break}return!1}function at(e,r){var t=(e.get(r)||0)-1;t>0?e.set(r,t):e.delete(r)}function Wt(e,r,t){at(t.pendingAdd,e);var n=t.delivery,a=e.parentNode;if(r===a&&!nt(e,t)&&!(n.holds(e)&&n.parentOf(e)===a)&&$(e,t.root,t.opts)===e&&n.holds(a)){var i=Ut(e,t);if(Te(e,t),!!n.holds(a)){var u=t.registry.peekId(a);if(u!=null){var s=K(e,t.span,t.opts);s&&(t.out.push({type:"dom.add",t:t.t,parent:u,before:i,node:s}),t.payloads.add(e),Kt(e,t))}}}}function Te(e,r){var t=r.delivery;if(t.holds(e)&&t.parentOf(e)!==e.parentNode){var n=r.registry.peekId(e);n!=null&&r.out.push({type:"dom.remove",t:r.t,node:n}),t.purge(e)}for(var a=e.childNodes||[],i=0;i<a.length;i++)Te(a[i],r)}function Ut(e,r){var t=e.nextSibling;if(!t)return null;var n=r.noHeldFrom.get(e.parentNode);if(n!==void 0&&(n===e||n===t))return null;for(var a=t;a;a=a.nextSibling)if(!(r.pending.get(a)>0)&&!(r.pendingAdd.get(a)>0)&&r.delivery.holds(a)&&r.delivery.parentOf(a)===e.parentNode){var i=r.registry.peekId(a);if(i!=null)return i}return r.noHeldFrom.set(e.parentNode,t),null}function Kt(e,r){var t=e.parentNode,n=r.noHeldFrom.get(t);if(n!==void 0){if(n===e){e.nextSibling?r.noHeldFrom.set(t,e.nextSibling):r.noHeldFrom.delete(t);return}e.nextSibling!==n&&r.noHeldFrom.delete(t)}}function Xt(e,r){var t=e.target,n=e.attributeName;if(!(!t||t.nodeType!==xe||!n)&&!r.transitioned.has(t)&&r.delivery.holds(t)&&$(t,r.root,r.opts)===t){var a=r.registry.peekId(t);if(a!=null&&!F(t,r.opts)){var i=it(t,e);if(i!==null){var u=le(t,r),s=be(t,i,u);if(s===ue){u&&D(t,r.opts.taint);return}se(t,i,r)!==et(t,i)&&r.out.push({type:"dom.attr",t:r.t,node:a,name:i,value:s})}}}}function it(e,r){var t=r.attributeNamespace;if(!t)return r.attributeName;for(var n=e.attributes||[],a=0;a<n.length;a++)if(n[a].localName===r.attributeName&&n[a].namespaceURI===t)return n[a].name;return null}function le(e,r){return U(e,r.opts.redactSelector)||ie(e,r.opts.taint)}function Yt(e,r){for(var t=e.parentNode;t;t=t.parentNode){if(r.restored.has(t))return!0;if(t===r.root)break}return!1}function Jt(e,r,t){if(Z(e,!1))for(var n=t.delivery.childrenOf(e),a=0;a<n.length;a++){var i=t.registry.peekId(n[a]);i!=null&&(t.out.push({type:"dom.remove",t:t.t,node:i}),t.delivery.purge(n[a]))}for(var u=le(e,t),s=_e(e,u),d=tt(e,t),a=0;a<d.length;a++)be(e,d[a].name,u)!==ue&&(s[d[a].name]=null);for(var g in s)Object.prototype.hasOwnProperty.call(s,g)&&t.out.push({type:"dom.attr",t:t.t,node:r,name:g,value:null})}function qt(e,r,t){var n=_e(e,le(e,t));for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&t.out.push({type:"dom.attr",t:t.t,node:r,name:a,value:n[a]});if(t.restored.add(e),t.payloads.add(e),!!Z(e,!1)){for(var i=e.childNodes||[],u=0;u<i.length;u++){var s=i[u];if(Q(s)&&!(t.delivery.holds(s)&&t.delivery.parentOf(s)===e)){Te(s,t);var d=K(s,t.span,t.opts);d&&(t.out.push({type:"dom.add",t:t.t,parent:r,before:null,node:d}),t.payloads.add(s))}}t.noHeldFrom.delete(e)}}function Qt(e,r){var t=e.target;if(r.delivery.holds(t)&&$(t,r.root,r.opts)===t){var n=r.registry.peekId(t);if(n!=null){if(le(t,r)){D(t,r.opts.taint);return}r.out.push({type:"dom.text",t:r.t,node:n,text:String(t.textContent==null?"":t.textContent)})}}}var Zt="video, audio",$t="input, textarea, select",er={password:!0,file:!0};function fe(e){return Math.round(e)}function tr(e){return Math.round(e*1e3)/1e3}function ot(e,r){if(typeof e.getAttribute=="function")return e.getAttribute(r);for(var t=e.attributes||[],n=0;n<t.length;n++)if(t[n].name===r)return t[n].value;return null}function rr(e,r){return ot(e,r)!==null}function ut(e,r){var t=[];if(typeof e.matches=="function")try{e.matches(r)&&t.push(e)}catch{}if(typeof e.querySelectorAll!="function")return t;for(var n=e.querySelectorAll(r),a=0;a<n.length;a++)t.push(n[a]);return t}function Re(e,r,t){return!r.delivery.holds(e)||F(e,t)?null:r.registry.peekId(e)}function Ce(e,r){return U(e,r.redactSelector)||W(e,r.taint)?(D(e,r.taint),!0):!1}function nr(e,r,t){var n=[],a=t.scrolled;return!a||typeof a.forEach!="function"||a.forEach(function(i){if(i&&!Ce(i,t)){var u=Re(i,r,t);if(u!==null){var s=fe(i.scrollLeft||0),d=fe(i.scrollTop||0);s===0&&d===0||n.push({node:u,x:s,y:d})}}}),n}function ar(e,r,t){for(var n=[],a=ut(e,Zt),i=0;i<a.length;i++){var u=a[i];if(!Ce(u,t)){var s=Re(u,r,t);if(s!==null){var d=typeof u.currentTime=="number"&&isFinite(u.currentTime)?tr(u.currentTime):0,g=u.paused!==!1;d===0&&g||n.push({node:s,current_time:d,paused:g})}}}return n}function ir(e){return typeof e.defaultValue=="string"?e.defaultValue:""}function Ee(e){return typeof e.value=="string"?e.value:String(e.textContent||"")}function or(e){if(typeof e.size=="number"&&e.size>0)return e.size;var r=parseInt(ot(e,"size"),10);return r>0?r:1}function ur(e){for(var r=e.options?Array.prototype.slice.call(e.options):[],t=[],n=[],a=null,i=0;i<r.length;i++){var u=r[i];u.selected&&t.push(Ee(u)),rr(u,"selected")&&n.push(Ee(u)),a===null&&!u.disabled&&(a=u)}return!e.multiple&&or(e)===1&&n.length===0&&a&&n.push(Ee(a)),t.length===n.length&&t.every(function(s,d){return s===n[d]})?null:{selected:t}}function sr(e){var r=e.tagName;if(r==="SELECT")return ur(e);if(r==="INPUT"){var t=String(e.type||"text").toLowerCase();if(er[t])return null;if(t==="checkbox"||t==="radio")return!!e.checked==!!e.defaultChecked?null:{checked:!!e.checked}}var n=typeof e.value=="string"?e.value:String(e.value==null?"":e.value);return n===ir(e)?null:{value:n}}function lr(e,r,t){for(var n=[],a=ut(e,$t),i=0;i<a.length;i++){var u=a[i];if(!Ce(u,t)){var s=Re(u,r,t);if(s!==null){var d=sr(u);d&&n.push(Object.assign({node:s},d))}}}return n}function st(e,r,t){if(t=t||{},!e||!r||r.registry.count===0)return null;var n=t.win!==void 0?t.win:typeof window<"u"?window:null,a={x:n?fe(n.scrollX||0):0,y:n?fe(n.scrollY||0):0},i={scroll:a,element_scroll:nr(e,r,t),media:ar(e,r,t),form:lr(e,r,t)};return a.x===0&&a.y===0&&!i.element_scroll.length&&!i.media.length&&!i.form.length?null:i}function lt(){let e=new WeakMap,r=1;function t(u){let s=e.get(u);return s!==void 0?s:(e.set(u,r),r++)}function n(u){let s=t(u),d=u.childNodes;if(d)for(let g=0;g<d.length;g++)n(d[g]);return s}function a(u){let s=e.get(u);return s===void 0?null:s}function i(){e=new WeakMap,r=1}return{idFor:t,assignTree:n,peekId:a,resetSpan:i,get count(){return r-1}}}function ft(){var e=new WeakMap,r=new WeakMap;function t(a){var i=e.get(a);if(i){var u=r.get(i);u&&u.delete(a)}}function n(a){var i=r.get(a);i&&(i.forEach(function(u){n(u)}),r.delete(a)),e.delete(a)}return{deliver:function(a,i){if(e.has(a)&&t(a),e.set(a,i||null),i){var u=r.get(i);u||(u=new Set,r.set(i,u)),u.add(a)}},purge:function(a){t(a),n(a)},holds:function(a){return e.has(a)},parentOf:function(a){var i=e.get(a);return i===void 0?null:i},childrenOf:function(a){var i=r.get(a);return i?Array.from(i):[]},reset:function(){e=new WeakMap,r=new WeakMap}}}function ee(){var e=lt(),r=ft();return{registry:e,delivery:r,reset:function(){e.resetSpan(),r.reset()}}}function fr(e){for(var r=[],t=e&&e.styleSheets||[],n=0;n<t.length;n++){var a=t[n],i=a.href||null,u=a.media&&a.media.mediaText?a.media.mediaText:null,s=null;try{for(var d=a.cssRules,g=[],S=0;S<d.length;S++)g.push(d[S].cssText);s=g.join(`
|
|
3
|
-
`)}catch{s=null}r.push(i?{id:n+1,kind:"link",href:i,css:s,media:u}:{id:n+1,kind:"inline",css:s??"",media:u})}return r}function dr(e,r){if(typeof r!="function"||!Array.isArray(e))return Promise.resolve();for(var t=[],n=0;n<e.length;n++){var a=e[n];!a||a.kind!=="link"||a.css!=null||typeof a.href!="string"||!/^https?:/i.test(a.href)||t.push(cr(a,r))}return Promise.all(t).then(function(){})}function cr(e,r){return Promise.resolve().then(function(){return r(e.href,{mode:"cors",credentials:"omit"})}).then(function(t){return!t||!t.ok?null:t.text()}).then(function(t){typeof t=="string"&&e.css==null&&(e.css=t)}).catch(function(){})}function de(e){if(e==null)return 0;try{return JSON.stringify(e).length}catch{return 0}}function pr(e,r){return!e.hasKeyframe||typeof r=="number"&&r>=1&&e.segments>=r?!0:e.lastSnapshotChars>0&&e.patchChars>=e.lastSnapshotChars}function dt(e,r){r=r||{};var t=r.doc||document,n=r.win||window,a=r.now||function(){return performance.now()},i=r.MutationObserver||(typeof MutationObserver<"u"?MutationObserver:null),u=r.span||ee(),s=typeof r.scrolled=="function"?r.scrolled:function(){return null},d={keepBait:e.config.keepBait,redactSelector:e.config.redactSelector,taint:r.taint},g=!1,S=x();function x(){var v=e.config.root;if(typeof v=="string"&&v){var b=null;try{b=t.querySelector(v)}catch{b=null}return b?(g=!0,b):(e.captureFailure("observed_root",new Error('root selector "'+v+'" matched nothing at startSession(); observing document.body instead')),t.body)}return v||t.body}function m(){return g?e.config.root:S&&S.id?"#"+S.id:null}e.setObservedRoot(m());try{var y=fr(t);e.setStylesheets(y);var R=t&&t.defaultView;R&&typeof R.fetch=="function"&&dr(y,R.fetch.bind(R))}catch(v){e.captureFailure("stylesheets",v)}var E={hasKeyframe:!1,segments:0,patchChars:0,lastSnapshotChars:0},O=e.config.keyframeEvery;O!=null&&typeof O!="number"&&console.warn("[cyborg-hunter-replay] keyframeEvery must be a number; got "+typeof O+" ("+JSON.stringify(O)+"). The segment fallback is DISABLED for this recording \u2014 keyframes will be taken on accumulated patch size alone."),e.onTrialStart(function(v){if(v.implicit&&E.hasKeyframe){E.segments++;return}if(!pr(E,e.config.keyframeEvery)){E.segments++;return}try{u.reset();var b=K(S,u,d),l=st(S,u,{win:n,scrolled:s(),keepBait:d.keepBait,redactSelector:d.redactSelector,taint:d.taint}),p=de(b)+de(l),w=e.config.maxCharsPerTrial;w!=null&&p>w?(e.captureFailure("dom_snapshot",new Error("initial DOM keyframe of "+p+" chars exceeds maxCharsPerTrial "+w+"; dropped to bound payload size")),v.initialDom=null,v.initialState=null,u.reset(),B()):(v.initialDom=b,v.initialState=l,e.noteSnapshotChars(v,p),E.hasKeyframe=!0,E.segments=1,E.patchChars=0,E.lastSnapshotChars=p)}catch(I){e.captureFailure("dom_snapshot",I),v.initialDom=null,v.initialState=null,u.reset(),B()}});function B(){E.hasKeyframe=!1,E.segments=0,E.patchChars=0,E.lastSnapshotChars=0}if(i){var A=function(v){try{for(var b=$e(v,{root:S,span:u,t:a(),keepBait:d.keepBait,redactSelector:d.redactSelector,taint:d.taint}),l=0;l<b.length;l++)e.pushRecord(b[l],b[l].t);b.length&&(E.patchChars+=de(b))}catch(p){e.captureFailure("mutations",p)}},M=new i(A);try{M.observe(S,Ze),e.addListener({addEventListener:function(){},removeEventListener:function(){}},"_mutation_observer",M,{_isObserver:!0}),e.addPreCloseFlush(function(){var v=M.takeRecords();v&&v.length&&A(v)})}catch(v){e.captureFailure("mutations",v)}}function V(){var v=K(S,ee(),d),b=e.config.maxCharsPerTrial;return b!=null&&de(v)>b?(e.captureFailure("guard_violation",new Error("pre-scramble DOM snapshot exceeds maxCharsPerTrial "+b+"; withheld")),null):v}if(n.GuardFriction&&typeof n.GuardFriction.onViolation=="function")try{var P=e.getState().state;if((P==="session"||P==="trial")&&typeof n.GuardFriction.getCurrentState=="function"){var k=n.GuardFriction.getCurrentState();k&&k.in_violation&&e.pushGuardViolation({reason:k.current_reason||"unknown",phase:"start",synthesized_at_subscribe:!0,dom_at_subscribe:V()},a())}n.GuardFriction.onViolation(function(v){try{v&&v.phase==="start"?e.pushGuardViolation({reason:v.reason,phase:"start",pre_scramble_dom:V()},a()):v&&v.phase&&e.pushGuardViolation({reason:v.reason,phase:v.phase,duration_ms:v.duration!=null?v.duration:null},a())}catch(b){e.captureFailure("guard_violation",b)}})}catch(v){e.captureFailure("guard_violation",v)}}var Ie="0.9.0";function ct(e){return String(e).replace(/[^a-zA-Z0-9_.-]/g,"_")}var ke=2;function G(e,r){return e==null?null:Math.round((e-r)*10)/10}function z(e,r){return(e||[]).map(function(t){var n=Object.assign({},t);return typeof n.t=="number"&&(n.t=G(n.t,r)),typeof n.start=="number"&&(n.start=G(n.start,r)),n})}function pt(e){return e.slice().sort(function(r,t){return r.t-t.t})}var hr={w:0,h:0,dpr:1,scale:1,offset_x:0,offset_y:0};function vr(e){return e?{w:X(e.w),h:X(e.h),dpr:X(e.dpr,1),scale:X(e.scale,1),offset_x:X(e.offset_x),offset_y:X(e.offset_y)}:Object.assign({},hr)}function X(e,r){return typeof e=="number"&&isFinite(e)?e:r??0}function ht(e,r){r=r||{};var t=e.sessionStart;if(t==null)throw new Error("[cyborg-hunter-replay] cannot serialize before startSession() \u2014 call startSession() first, or the timestamps would be meaningless (Unix epoch).");var n=r.chSessionReport||null,a=t,i=e.trials.map(function(s,d){var g=pt(s.events),S=g.length>0?g[g.length-1].t:s.tLoad;return S>a&&(a=S),s.tEnd!=null&&s.tEnd>a&&(a=s.tEnd),{index:d,label:s.trialId!=null?s.trialId:null,plugin:s.plugin!=null?s.plugin:null,t_start:G(s.tStart,t),t_dom_ready:G(s.tDomReady,t),t_load:G(s.tLoad,t),t_end:G(s.tEnd!=null?s.tEnd:S,t),initial_dom:s.initialDom||null,initial_state:s.initialState||null,events:g.map(function(x){var m=Object.assign({},x);return m.t=G(x.t,t),m}),host_data:s.hostData!=null?s.hostData:null,extensions:s.implicit?{"cyborg-hunter":{implicit:!0}}:null}}),u={replay_version:Ie,tier:e.tier,keys:e.keys,viewport_client:e.viewportClient||null,ch_version:n&&n.libraryVersion||null,preset:n&&n.config?n.config.preset:null,scoring:n?{hard_score:n.hardScore||{},soft_score:n.softScore!=null?n.softScore:null,soft_score_threshold:n.softScoreThreshold!=null?n.softScoreThreshold:null,any_hard_triggered:!!n.anyHardTriggered,trials_completed:n.trialsCompleted!=null?n.trialsCompleted:null}:null,session_signals:n?{sidebar_events:z(n.sidebarEvents,t),ai_extensions_found:z(n.aiExtensionsFound,t),devtools_events:z(n.devToolsEvents,t),window_positions:z(n.windowPositions,t),layout_shifts:z(n.layoutShifts,t),zoom_changes:z(n.zoomChanges,t),extension_injections:z(n.extensionInjections,t)}:null,guard_violations:z(e.guardViolations,t),capture_failures:z(e.captureFailures,t),capture_stopped:!!e.captureStopped,inherited_redaction_taint:!!e.inheritedRedactionTaint};return{schema_version:ke,recorder:{name:"cyborg-hunter-replay",version:Ie},host:r.host||null,participant_id:e.participantId!=null?e.participantId:null,recording_started_at:new Date(e.sessionStartEpoch).toISOString(),recording_started_at_perf:t,user_agent:e.userAgent||"",viewport:vr(e.viewport),observed_root:e.observedRoot||null,stylesheets:e.stylesheets||[],stylesheet_events:[],viewport_changes:pt(e.viewportChanges||[]).map(function(s){var d=Object.assign({},s);return d.t=G(s.t,t),d}),rng:null,rng_calls:null,ended_at_perf:a,end_reason:e.endReason||"aborted",truncated:!!e.captureStopped,extensions:{"cyborg-hunter":u},segments:i}}var mr="https://pipe.jspsych.org/api/data/";function yr(e){var r=e&&e.extensions;return r&&r["cyborg-hunter"]||{}}function vt(e){var r=ct(e.participant_id),t=Date.parse(e.recording_started_at);return r+"-replay-"+t+".json"}function mt(e,r){var t=yr(e);return{schema_version:e.schema_version,tier:t.tier!=null?t.tier:null,saved_to:r,bytes_uncompressed:JSON.stringify(e).length,capture_failures:(t.capture_failures||[]).map(function(n){return n.channel}),capture_stopped:!!e.truncated}}async function yt(e,r){var t=r||{mode:"none"},n=vt(e),a=typeof window<"u"?window:{};if(t.mode==="none")return{saved_to:"none",filename:n};if(t.mode==="datapipe"){if(!t.experimentId)return{saved_to:"failed",filename:n,error:'autoSave.mode "datapipe" requires autoSave.experimentId'};try{var i=JSON.stringify(e);if(a.jsPsychPipe&&typeof a.jsPsychPipe.saveData=="function")await a.jsPsychPipe.saveData(t.experimentId,n,i);else{var u=a.fetch||(typeof fetch<"u"?fetch:null);if(!u)throw new Error("no fetch available for DataPipe POST");var s=await u(mr,{method:"POST",headers:{"Content-Type":"application/json",Accept:"*/*"},body:JSON.stringify({experimentID:t.experimentId,filename:n,data:i})});if(s&&s.ok===!1)throw new Error("DataPipe HTTP error")}return{saved_to:"datapipe:"+t.experimentId+"/"+n,filename:n}}catch(y){return console.error("[cyborg-hunter-replay] DataPipe autosave failed:",y),{saved_to:"failed",filename:n,error:y&&y.message?y.message:String(y)}}}if(t.mode==="download")try{var d=typeof document<"u"?document:null,g=a.Blob||(typeof Blob<"u"?Blob:null),S=a.URL||(typeof URL<"u"?URL:null);if(!d||!g||!S)throw new Error("download mode needs a browser");var x=new g([JSON.stringify(e)],{type:"application/json"}),m=d.createElement("a");return m.href=S.createObjectURL(x),m.download=n,d.body.appendChild(m),m.click(),d.body.removeChild(m),S.revokeObjectURL(m.href),{saved_to:"download",filename:n}}catch(y){return console.error("[cyborg-hunter-replay] download autosave failed:",y),{saved_to:"failed",filename:n,error:y&&y.message?y.message:String(y)}}return{saved_to:"failed",filename:n,error:'unknown autoSave.mode "'+t.mode+'"'}}async function gt(e){var r=JSON.stringify(e),t=typeof window<"u"?window:{},n=t.CompressionStream||(typeof CompressionStream<"u"?CompressionStream:null),a=t.Blob||(typeof Blob<"u"?Blob:null);if(!a)return null;if(!n)return new a([r],{type:"application/json"});var i=new a([r]).stream().pipeThrough(new n("gzip")),u=t.Response||(typeof Response<"u"?Response:null),s=await new u(i).arrayBuffer();return new a([s],{type:"application/gzip"})}var Y=null;function Ne(e){Y&&(console.warn("[cyborg-hunter-replay] attach() called while a recorder is active \u2014 replacing the previous instance (its unsaved recording is discarded)."),Y.destroy(),Y=null);var r=je(e),t={_recorder:r,config:r.config,startSession:function(){r.startSession();var n=ee(),a=Qe(r,{span:n});return(r.config.tier==="dom"||r.config.tier==="canvas")&&dt(r,{span:n,scrolled:a.getScrolledElements}),t},startTrial:function(n){return r.startTrial(n),t},endTrial:function(){return r.endTrial(),t},stopSession:function(n){return r.stopSession(n),t},getRecording:function(n){return ht(r.getState(),n||{})},getRecordingCompressed:function(n){return gt(t.getRecording(n))},autoSaveNow:async function(n){if(r.getState().sessionStart==null)return{recording:null,saveResult:{saved_to:"no_session"},meta:{schema_version:ke,saved_to:"no_session",note:"recorder was never started; nothing to save"}};var a=t.getRecording(n),i=await yt(a,r.config.autoSave),u=mt(a,i.saved_to);return i.error&&(u.save_error=i.error),{recording:a,saveResult:i,meta:u}},destroy:function(){r.destroy(),Y===t&&(Y=null)}};return Y=t,t}typeof window<"u"&&(window.CyborgHunterReplay={attach:Ne});var Pe=class{static info={name:"cyborg-hunter-replay",version:"0.9.0",data:{}};constructor(r){this.jsPsych=r,this.api=null,this._chMonitor=null,this._lastRecording=null,this._monitoring=!1}initialize(r){this.params=r||{},this.params.keyframeEvery!=null&&this.params.keyframeEvery!==1&&console.warn("[cyborg-hunter-replay] ignoring keyframeEvery: "+this.params.keyframeEvery+" \u2014 jsPsych wipes the display between trials, so every trial segment is recorded as a keyframe."),this.api=Ne(Object.assign({},this.params,{keyframeEvery:1})),this.api.startSession(),this._stashChMonitor()}_stashChMonitor(){try{var r=this.jsPsych&&this.jsPsych.extensions&&this.jsPsych.extensions["cyborg-hunter"];r&&r.monitor&&(this._chMonitor=r.monitor)}catch{}}_detectHost(){try{var r=this.jsPsych;if(!r||typeof r.version!="function")return null;var t=r.version();return typeof t!="string"||!t?null:{name:"jspsych",version:t}}catch{return null}}on_start(r){}on_load(r){if(this.api){this._monitoring=!0;var t=0,n="unknown";try{t=this.jsPsych.getProgress().current_trial_global}catch{}try{n=(this.jsPsych.getCurrentTrial()||{}).type?.info?.name||"unknown"}catch{}this.api.startTrial({trialId:r&&r.trialId||"trial-"+t,plugin:n})}}on_finish(r){return this.api&&this._monitoring&&(this._monitoring=!1,this.api.endTrial()),{}}async finalize(){if(this.api){try{try{this.api.stopSession("finished")}catch{}this._chMonitor||this._stashChMonitor();var r=null;try{r=this._chMonitor?this._chMonitor.getSessionReport():null}catch(n){console.warn("[cyborg-hunter-replay] could not pull CH session report:",n)}var t=await this.api.autoSaveNow({chSessionReport:r,host:this._detectHost()});this._lastRecording=t.recording,this.jsPsych.data.addProperties({integrityReplayMeta:t.meta})}catch(n){console.warn("[cyborg-hunter-replay] finalize failed:",n);try{this.jsPsych.data.addProperties({replayFinalizeError:String(n&&n.message?n.message:n)})}catch{}}try{this.api.destroy()}catch{}this.api=null}}getLastRecording(){return this._lastRecording}};typeof window<"u"&&(window.jsPsychCyborgHunterReplay=Pe);})();
|
|
3
|
+
`)}catch{s=null}r.push(i?{id:n+1,kind:"link",href:i,css:s,media:u}:{id:n+1,kind:"inline",css:s??"",media:u})}return r}function dr(e,r){if(typeof r!="function"||!Array.isArray(e))return Promise.resolve();for(var t=[],n=0;n<e.length;n++){var a=e[n];!a||a.kind!=="link"||a.css!=null||typeof a.href!="string"||!/^https?:/i.test(a.href)||t.push(cr(a,r))}return Promise.all(t).then(function(){})}function cr(e,r){return Promise.resolve().then(function(){return r(e.href,{mode:"cors",credentials:"omit"})}).then(function(t){return!t||!t.ok?null:t.text()}).then(function(t){typeof t=="string"&&e.css==null&&(e.css=t)}).catch(function(){})}function de(e){if(e==null)return 0;try{return JSON.stringify(e).length}catch{return 0}}function pr(e,r){return!e.hasKeyframe||typeof r=="number"&&r>=1&&e.segments>=r?!0:e.lastSnapshotChars>0&&e.patchChars>=e.lastSnapshotChars}function dt(e,r){r=r||{};var t=r.doc||document,n=r.win||window,a=r.now||function(){return performance.now()},i=r.MutationObserver||(typeof MutationObserver<"u"?MutationObserver:null),u=r.span||ee(),s=typeof r.scrolled=="function"?r.scrolled:function(){return null},d={keepBait:e.config.keepBait,redactSelector:e.config.redactSelector,taint:r.taint},g=!1,S=x();function x(){var v=e.config.root;if(typeof v=="string"&&v){var b=null;try{b=t.querySelector(v)}catch{b=null}return b?(g=!0,b):(e.captureFailure("observed_root",new Error('root selector "'+v+'" matched nothing at startSession(); observing document.body instead')),t.body)}return v||t.body}function m(){return g?e.config.root:S&&S.id?"#"+S.id:null}e.setObservedRoot(m());try{var y=fr(t);e.setStylesheets(y);var R=t&&t.defaultView;R&&typeof R.fetch=="function"&&dr(y,R.fetch.bind(R))}catch(v){e.captureFailure("stylesheets",v)}var E={hasKeyframe:!1,segments:0,patchChars:0,lastSnapshotChars:0},O=e.config.keyframeEvery;O!=null&&typeof O!="number"&&console.warn("[cyborg-hunter-replay] keyframeEvery must be a number; got "+typeof O+" ("+JSON.stringify(O)+"). The segment fallback is DISABLED for this recording \u2014 keyframes will be taken on accumulated patch size alone."),e.onTrialStart(function(v){if(v.implicit&&E.hasKeyframe){E.segments++;return}if(!pr(E,e.config.keyframeEvery)){E.segments++;return}try{u.reset();var b=K(S,u,d),l=st(S,u,{win:n,scrolled:s(),keepBait:d.keepBait,redactSelector:d.redactSelector,taint:d.taint}),p=de(b)+de(l),w=e.config.maxCharsPerTrial;w!=null&&p>w?(e.captureFailure("dom_snapshot",new Error("initial DOM keyframe of "+p+" chars exceeds maxCharsPerTrial "+w+"; dropped to bound payload size")),v.initialDom=null,v.initialState=null,u.reset(),B()):(v.initialDom=b,v.initialState=l,e.noteSnapshotChars(v,p),E.hasKeyframe=!0,E.segments=1,E.patchChars=0,E.lastSnapshotChars=p)}catch(I){e.captureFailure("dom_snapshot",I),v.initialDom=null,v.initialState=null,u.reset(),B()}});function B(){E.hasKeyframe=!1,E.segments=0,E.patchChars=0,E.lastSnapshotChars=0}if(i){var A=function(v){try{for(var b=$e(v,{root:S,span:u,t:a(),keepBait:d.keepBait,redactSelector:d.redactSelector,taint:d.taint}),l=0;l<b.length;l++)e.pushRecord(b[l],b[l].t);b.length&&(E.patchChars+=de(b))}catch(p){e.captureFailure("mutations",p)}},M=new i(A);try{M.observe(S,Ze),e.addListener({addEventListener:function(){},removeEventListener:function(){}},"_mutation_observer",M,{_isObserver:!0}),e.addPreCloseFlush(function(){var v=M.takeRecords();v&&v.length&&A(v)})}catch(v){e.captureFailure("mutations",v)}}function V(){var v=K(S,ee(),d),b=e.config.maxCharsPerTrial;return b!=null&&de(v)>b?(e.captureFailure("guard_violation",new Error("pre-scramble DOM snapshot exceeds maxCharsPerTrial "+b+"; withheld")),null):v}if(n.GuardFriction&&typeof n.GuardFriction.onViolation=="function")try{var P=e.getState().state;if((P==="session"||P==="trial")&&typeof n.GuardFriction.getCurrentState=="function"){var k=n.GuardFriction.getCurrentState();k&&k.in_violation&&e.pushGuardViolation({reason:k.current_reason||"unknown",phase:"start",synthesized_at_subscribe:!0,dom_at_subscribe:V()},a())}n.GuardFriction.onViolation(function(v){try{v&&v.phase==="start"?e.pushGuardViolation({reason:v.reason,phase:"start",pre_scramble_dom:V()},a()):v&&v.phase&&e.pushGuardViolation({reason:v.reason,phase:v.phase,duration_ms:v.duration!=null?v.duration:null},a())}catch(b){e.captureFailure("guard_violation",b)}})}catch(v){e.captureFailure("guard_violation",v)}}var Ie="0.9.1";function ct(e){return String(e).replace(/[^a-zA-Z0-9_.-]/g,"_")}var ke=2;function G(e,r){return e==null?null:Math.round((e-r)*10)/10}function z(e,r){return(e||[]).map(function(t){var n=Object.assign({},t);return typeof n.t=="number"&&(n.t=G(n.t,r)),typeof n.start=="number"&&(n.start=G(n.start,r)),n})}function pt(e){return e.slice().sort(function(r,t){return r.t-t.t})}var hr={w:0,h:0,dpr:1,scale:1,offset_x:0,offset_y:0};function vr(e){return e?{w:X(e.w),h:X(e.h),dpr:X(e.dpr,1),scale:X(e.scale,1),offset_x:X(e.offset_x),offset_y:X(e.offset_y)}:Object.assign({},hr)}function X(e,r){return typeof e=="number"&&isFinite(e)?e:r??0}function ht(e,r){r=r||{};var t=e.sessionStart;if(t==null)throw new Error("[cyborg-hunter-replay] cannot serialize before startSession() \u2014 call startSession() first, or the timestamps would be meaningless (Unix epoch).");var n=r.chSessionReport||null,a=t,i=e.trials.map(function(s,d){var g=pt(s.events),S=g.length>0?g[g.length-1].t:s.tLoad;return S>a&&(a=S),s.tEnd!=null&&s.tEnd>a&&(a=s.tEnd),{index:d,label:s.trialId!=null?s.trialId:null,plugin:s.plugin!=null?s.plugin:null,t_start:G(s.tStart,t),t_dom_ready:G(s.tDomReady,t),t_load:G(s.tLoad,t),t_end:G(s.tEnd!=null?s.tEnd:S,t),initial_dom:s.initialDom||null,initial_state:s.initialState||null,events:g.map(function(x){var m=Object.assign({},x);return m.t=G(x.t,t),m}),host_data:s.hostData!=null?s.hostData:null,extensions:s.implicit?{"cyborg-hunter":{implicit:!0}}:null}}),u={replay_version:Ie,tier:e.tier,keys:e.keys,viewport_client:e.viewportClient||null,ch_version:n&&n.libraryVersion||null,preset:n&&n.config?n.config.preset:null,scoring:n?{hard_score:n.hardScore||{},soft_score:n.softScore!=null?n.softScore:null,soft_score_threshold:n.softScoreThreshold!=null?n.softScoreThreshold:null,any_hard_triggered:!!n.anyHardTriggered,trials_completed:n.trialsCompleted!=null?n.trialsCompleted:null}:null,session_signals:n?{sidebar_events:z(n.sidebarEvents,t),ai_extensions_found:z(n.aiExtensionsFound,t),devtools_events:z(n.devToolsEvents,t),window_positions:z(n.windowPositions,t),layout_shifts:z(n.layoutShifts,t),zoom_changes:z(n.zoomChanges,t),extension_injections:z(n.extensionInjections,t)}:null,guard_violations:z(e.guardViolations,t),capture_failures:z(e.captureFailures,t),capture_stopped:!!e.captureStopped,inherited_redaction_taint:!!e.inheritedRedactionTaint};return{schema_version:ke,recorder:{name:"cyborg-hunter-replay",version:Ie},host:r.host||null,participant_id:e.participantId!=null?e.participantId:null,recording_started_at:new Date(e.sessionStartEpoch).toISOString(),recording_started_at_perf:t,user_agent:e.userAgent||"",viewport:vr(e.viewport),observed_root:e.observedRoot||null,stylesheets:e.stylesheets||[],stylesheet_events:[],viewport_changes:pt(e.viewportChanges||[]).map(function(s){var d=Object.assign({},s);return d.t=G(s.t,t),d}),rng:null,rng_calls:null,ended_at_perf:a,end_reason:e.endReason||"aborted",truncated:!!e.captureStopped,extensions:{"cyborg-hunter":u},segments:i}}var mr="https://pipe.jspsych.org/api/data/";function yr(e){var r=e&&e.extensions;return r&&r["cyborg-hunter"]||{}}function vt(e){var r=ct(e.participant_id),t=Date.parse(e.recording_started_at);return r+"-replay-"+t+".json"}function mt(e,r){var t=yr(e);return{schema_version:e.schema_version,tier:t.tier!=null?t.tier:null,saved_to:r,bytes_uncompressed:JSON.stringify(e).length,capture_failures:(t.capture_failures||[]).map(function(n){return n.channel}),capture_stopped:!!e.truncated}}async function yt(e,r){var t=r||{mode:"none"},n=vt(e),a=typeof window<"u"?window:{};if(t.mode==="none")return{saved_to:"none",filename:n};if(t.mode==="datapipe"){if(!t.experimentId)return{saved_to:"failed",filename:n,error:'autoSave.mode "datapipe" requires autoSave.experimentId'};try{var i=JSON.stringify(e);if(a.jsPsychPipe&&typeof a.jsPsychPipe.saveData=="function")await a.jsPsychPipe.saveData(t.experimentId,n,i);else{var u=a.fetch||(typeof fetch<"u"?fetch:null);if(!u)throw new Error("no fetch available for DataPipe POST");var s=await u(mr,{method:"POST",headers:{"Content-Type":"application/json",Accept:"*/*"},body:JSON.stringify({experimentID:t.experimentId,filename:n,data:i})});if(s&&s.ok===!1)throw new Error("DataPipe HTTP error")}return{saved_to:"datapipe:"+t.experimentId+"/"+n,filename:n}}catch(y){return console.error("[cyborg-hunter-replay] DataPipe autosave failed:",y),{saved_to:"failed",filename:n,error:y&&y.message?y.message:String(y)}}}if(t.mode==="download")try{var d=typeof document<"u"?document:null,g=a.Blob||(typeof Blob<"u"?Blob:null),S=a.URL||(typeof URL<"u"?URL:null);if(!d||!g||!S)throw new Error("download mode needs a browser");var x=new g([JSON.stringify(e)],{type:"application/json"}),m=d.createElement("a");return m.href=S.createObjectURL(x),m.download=n,d.body.appendChild(m),m.click(),d.body.removeChild(m),S.revokeObjectURL(m.href),{saved_to:"download",filename:n}}catch(y){return console.error("[cyborg-hunter-replay] download autosave failed:",y),{saved_to:"failed",filename:n,error:y&&y.message?y.message:String(y)}}return{saved_to:"failed",filename:n,error:'unknown autoSave.mode "'+t.mode+'"'}}async function gt(e){var r=JSON.stringify(e),t=typeof window<"u"?window:{},n=t.CompressionStream||(typeof CompressionStream<"u"?CompressionStream:null),a=t.Blob||(typeof Blob<"u"?Blob:null);if(!a)return null;if(!n)return new a([r],{type:"application/json"});var i=new a([r]).stream().pipeThrough(new n("gzip")),u=t.Response||(typeof Response<"u"?Response:null),s=await new u(i).arrayBuffer();return new a([s],{type:"application/gzip"})}var Y=null;function Ne(e){Y&&(console.warn("[cyborg-hunter-replay] attach() called while a recorder is active \u2014 replacing the previous instance (its unsaved recording is discarded)."),Y.destroy(),Y=null);var r=je(e),t={_recorder:r,config:r.config,startSession:function(){r.startSession();var n=ee(),a=Qe(r,{span:n});return(r.config.tier==="dom"||r.config.tier==="canvas")&&dt(r,{span:n,scrolled:a.getScrolledElements}),t},startTrial:function(n){return r.startTrial(n),t},endTrial:function(){return r.endTrial(),t},stopSession:function(n){return r.stopSession(n),t},getRecording:function(n){return ht(r.getState(),n||{})},getRecordingCompressed:function(n){return gt(t.getRecording(n))},autoSaveNow:async function(n){if(r.getState().sessionStart==null)return{recording:null,saveResult:{saved_to:"no_session"},meta:{schema_version:ke,saved_to:"no_session",note:"recorder was never started; nothing to save"}};var a=t.getRecording(n),i=await yt(a,r.config.autoSave),u=mt(a,i.saved_to);return i.error&&(u.save_error=i.error),{recording:a,saveResult:i,meta:u}},destroy:function(){r.destroy(),Y===t&&(Y=null)}};return Y=t,t}typeof window<"u"&&(window.CyborgHunterReplay={attach:Ne});var Pe=class{static info={name:"cyborg-hunter-replay",version:"0.9.1",data:{}};constructor(r){this.jsPsych=r,this.api=null,this._chMonitor=null,this._lastRecording=null,this._monitoring=!1}initialize(r){this.params=r||{},this.params.keyframeEvery!=null&&this.params.keyframeEvery!==1&&console.warn("[cyborg-hunter-replay] ignoring keyframeEvery: "+this.params.keyframeEvery+" \u2014 jsPsych wipes the display between trials, so every trial segment is recorded as a keyframe."),this.api=Ne(Object.assign({},this.params,{keyframeEvery:1})),this.api.startSession(),this._stashChMonitor()}_stashChMonitor(){try{var r=this.jsPsych&&this.jsPsych.extensions&&this.jsPsych.extensions["cyborg-hunter"];r&&r.monitor&&(this._chMonitor=r.monitor)}catch{}}_detectHost(){try{var r=this.jsPsych;if(!r||typeof r.version!="function")return null;var t=r.version();return typeof t!="string"||!t?null:{name:"jspsych",version:t}}catch{return null}}on_start(r){}on_load(r){if(this.api){this._monitoring=!0;var t=0,n="unknown";try{t=this.jsPsych.getProgress().current_trial_global}catch{}try{n=(this.jsPsych.getCurrentTrial()||{}).type?.info?.name||"unknown"}catch{}this.api.startTrial({trialId:r&&r.trialId||"trial-"+t,plugin:n})}}on_finish(r){return this.api&&this._monitoring&&(this._monitoring=!1,this.api.endTrial()),{}}async finalize(){if(this.api){try{try{this.api.stopSession("finished")}catch{}this._chMonitor||this._stashChMonitor();var r=null;try{r=this._chMonitor?this._chMonitor.getSessionReport():null}catch(n){console.warn("[cyborg-hunter-replay] could not pull CH session report:",n)}var t=await this.api.autoSaveNow({chSessionReport:r,host:this._detectHost()});this._lastRecording=t.recording,this.jsPsych.data.addProperties({integrityReplayMeta:t.meta})}catch(n){console.warn("[cyborg-hunter-replay] finalize failed:",n);try{this.jsPsych.data.addProperties({replayFinalizeError:String(n&&n.message?n.message:n)})}catch{}}try{this.api.destroy()}catch{}this.api=null}}getLastRecording(){return this._lastRecording}};typeof window<"u"&&(window.jsPsychCyborgHunterReplay=Pe);})();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// cyborg-hunter v0.9.
|
|
2
|
-
var CyborgHunter=(()=>{var _=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var Ee=Object.prototype.hasOwnProperty;var Ie=(e,n)=>{for(var t in n)_(e,t,{get:n[t],enumerable:!0})},Me=(e,n,t,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of be(n))!Ee.call(e,r)&&r!==t&&_(e,r,{get:()=>n[r],enumerable:!(o=Te(n,r))||o.enumerable});return e};var xe=e=>Me(_({},"__esModule",{value:!0}),e);var Fe={};Ie(Fe,{VERSION:()=>q,addHoneypot:()=>me,init:()=>we,preventTextSelection:()=>ve,setAltText:()=>ye});var W={created:["session","destroyed"],session:["trial","destroyed"],trial:["session","destroyed"],destroyed:[]};function J(){let e="created";return{get current(){return e},transition(n){return W[e]&&W[e].indexOf(n)!==-1?(e=n,!0):(console.warn("[cyborg-hunter] invalid transition: "+e+" \u2192 "+n),!1)}}}function N(e){if(e===null||typeof e!="object")return e;try{return JSON.parse(JSON.stringify(e))}catch{return e}}var q="0.9.0",z={pasteMinChars:0,dropMinChars:0,sidebarGapPx:100,layoutCompressionPx:20,viewportShiftDebounceMs:250,syntheticGapMs:100,idleGapMs:1e4,idleCheckIntervalMs:5e3,mouseThrottleMs:50,mouseMaxEvents:2e3,mouseBotMinEvents:3,sidebarPollMs:2e3,extensionScanMs:3e4,windowPositionPollMs:2e3,elementTraceHz:500,tabAwayDurationMs:3e3,typingSpeedCps:10},$={permissive:{signals:{paste:!0,copy:!0,drop:!0,tabAway:!0,typingSpeed:!0,devTools:!0,aiExtensions:!0,sidebarGap:!0,keyboardShortcuts:!0,mouseTracking:!0,idleGaps:!0,windowPosition:!0,clipboardManager:!0,keystrokeDynamics:!1},thresholds:{typingSpeedCps:15},scoring:{hard:{paste:{countThreshold:3},drop:{countThreshold:3}},soft:{copy:{weight:1,maxPerTrial:2},tabAway:{weight:1,maxPerTrial:2},typingSpeed:{weight:1},sidebarEvent:{weight:1},devTools:{weight:1},foreignInput:{weight:1}},softScoreThreshold:10},screenout:{enabled:!1,gracePeriodTrials:5}},standard:{signals:{paste:!0,copy:!0,drop:!0,tabAway:!0,typingSpeed:!0,devTools:!0,aiExtensions:!0,sidebarGap:!0,keyboardShortcuts:!0,mouseTracking:!0,idleGaps:!0,windowPosition:!0,clipboardManager:!0,keystrokeDynamics:!1},thresholds:{},scoring:{hard:{paste:{countThreshold:2},drop:{countThreshold:2}},soft:{copy:{weight:2,maxPerTrial:2},tabAway:{weight:1,maxPerTrial:2},typingSpeed:{weight:2},sidebarEvent:{weight:3},devTools:{weight:1},foreignInput:{weight:2}},softScoreThreshold:6},screenout:{enabled:!0,gracePeriodTrials:3}},strict:{signals:{paste:!0,copy:!0,drop:!0,tabAway:!0,typingSpeed:!0,devTools:!0,aiExtensions:!0,sidebarGap:!0,keyboardShortcuts:!0,mouseTracking:!0,idleGaps:!0,windowPosition:!0,clipboardManager:!0,keystrokeDynamics:!0},thresholds:{typingSpeedCps:8,tabAwayDurationMs:5e3,mouseMaxEvents:5e3},scoring:{hard:{paste:{countThreshold:1},copy:{countThreshold:2},drop:{countThreshold:1}},soft:{tabAway:{weight:2,maxPerTrial:1},typingSpeed:{weight:3},sidebarEvent:{weight:2},devTools:{weight:2},foreignInput:{weight:3}},softScoreThreshold:4},screenout:{enabled:!0,gracePeriodTrials:2}}},X=[{name:"ChatGPT sidebar",sel:"chatgpt-sidebar"},{name:"ChatGPT extension",sel:"[data-chatgpt]"},{name:"Copilot extension",sel:"copilot-suggestions"},{name:"Copilot extension",sel:"[data-copilot]"},{name:"Gemini extension",sel:"gemini-panel"},{name:"Claude extension",sel:"[data-claude-extension]"},{name:"Monica AI",sel:"monica-root"},{name:"Merlin AI",sel:"merlin-root"},{name:"Sider AI",sel:"[data-sider-extension]"},{name:"MaxAI",sel:"[data-maxai]"},{name:"AI assistant",sel:"[data-ai-assistant]"},{name:"AI iframe (OpenAI)",sel:'iframe[src*="chat.openai.com"]'},{name:"AI iframe (Copilot)",sel:'iframe[src*="copilot.microsoft.com"]'},{name:"AI iframe (Gemini)",sel:'iframe[src*="gemini.google.com"]'},{name:"AI iframe (Claude)",sel:'iframe[src*="claude.ai"]'},{name:"AI iframe (Perplexity)",sel:'iframe[src*="perplexity.ai"]'}],Y=["grammarly","lastpass","1password","bitwarden","dashlane","roboform","honey","ublock","adblock"];var Q={dataDir:"./data",replayDir:null,scoreWeights:null,filePattern:"*.json",participantIdField:"participantId",trialIdField:"trialId",trialOrderField:"trialIndex",integrityField:"integrity",sessionIntegrityPath:null,trialsPerParticipant:null,platformIdField:null,showPlatformId:!1,conditionField:null,groupField:null,typingSpeedThreshold_cps:10,tabAwayMinDuration_ms:3e3,idleGapThreshold_ms:1e4,suspiciouslyFastRT_ms:2e3,scoring:null,signals:null,phaseScope:null,trajectoryGrid:"auto",trajectoryTrialLabel:"trialId",trajectoryResponseField:null,trajectoryDisplayOrder:"rule",outputDir:"./cyborg-hunter-report",outputFormat:"html"};var Ce=["replayDir",...Object.keys(Q),...Object.keys(z),"preset","participantId","signals","thresholds","scoring","domProtection","collectForPostHoc","onSignal","screenout","experimentContainer","knownInputs","decoyAnswers","decoyMap","decoyVisibility","decoyFraming","decoyExcludeButtons","autoMonitor","excludeTrialTypes"];function ee(e,n=Ce){let t=[];return Object.keys(e).forEach(o=>{if(!n.includes(o)){let r=Ae(o,n),i=r?`Unknown config key "${o}" \u2014 did you mean "${r}"?`:`Unknown config key "${o}"`;t.push(i)}}),t}function te(e){let n=[];if(!e||typeof e!="object")return n;let t=e.hard||{};Object.keys(t).forEach(r=>{let i=t[r];(!i||!Number.isFinite(i.countThreshold))&&n.push(`scoring.hard.${r} has no finite numeric countThreshold (got ${i?Z(i.countThreshold):"no rule"}) \u2014 this hard screenout rule can never trigger. A likely cause is a typo in the override key (e.g. "countThreshhold").`)});let o=e.soft||{};return Object.keys(o).forEach(r=>{let i=o[r];(!i||!Number.isFinite(i.weight))&&n.push(`scoring.soft.${r} has no finite numeric weight (got ${i?Z(i.weight):"no rule"}) \u2014 this soft signal contributes nothing (or breaks the soft score). A likely cause is a typo in the override key (e.g. "wieght").`)}),n}function Z(e){try{return String(e)}catch{return typeof e}}function Ae(e,n){let t=null,o=1/0;for(let r of n){let i=Pe(e.toLowerCase(),r.toLowerCase());i<o&&i<=3&&(o=i,t=r)}return t}function Pe(e,n){let t=e.length,o=n.length,r=Array.from({length:t+1},()=>Array(o+1).fill(0));for(let i=0;i<=t;i++)r[i][0]=i;for(let i=0;i<=o;i++)r[0][i]=i;for(let i=1;i<=t;i++)for(let a=1;a<=o;a++)r[i][a]=e[i-1]===n[a-1]?r[i-1][a-1]:1+Math.min(r[i-1][a],r[i][a-1],r[i-1][a-1]);return r[t][o]}function re(e,n,t,o){var r=t.scoring,i={hard:{},soft:{}},a=0;if(r.hard.paste){var c=(e.pasteEvents||[]).length;i.hard.paste={trialHits:c,sessionTotal:n.pasteCount,countThreshold:r.hard.paste.countThreshold}}if(r.hard.copy){var v=(e.copyEvents||[]).length;i.hard.copy={trialHits:v,sessionTotal:n.copyCount,countThreshold:r.hard.copy.countThreshold}}if(r.hard.drop){var d=(e.dropEvents||[]).length;i.hard.drop={trialHits:d,sessionTotal:n.dropCount,countThreshold:r.hard.drop.countThreshold}}if(r.soft.copy){var h=(e.copyEvents||[]).length,m=r.soft.copy.maxPerTrial!=null?Math.min(h,r.soft.copy.maxPerTrial):h,T=m*r.soft.copy.weight;a+=T,i.soft.copy={hits:h,capped:m,score:T}}if(r.soft.tabAway){var y=(e.tabAwayEvents||[]).filter(function(F){return(F.duration_ms||0)>t.thresholds.tabAwayDurationMs}).length,k=r.soft.tabAway.maxPerTrial!=null?Math.min(y,r.soft.tabAway.maxPerTrial):y,M=k*r.soft.tabAway.weight;a+=M,i.soft.tabAway={hits:y,capped:k,score:M}}if(r.soft.typingSpeed&&o.charsPerSec!=null){var b=t.thresholds.typingSpeedCps,E=o.charsPerSec>b?1:0,u=E*r.soft.typingSpeed.weight;a+=u,i.soft.typingSpeed={charsPerSec:o.charsPerSec,threshold:b,hit:E,score:u}}var p=e.startTime+(o&&o.duration_ms!=null?o.duration_ms:performance.now()-e.startTime);if(r.soft.sidebarEvent){var S=n.sidebarEvents.filter(function(F){return F.t>=e.startTime&&F.t<=p}).length;if(S>0){var l=r.soft.sidebarEvent.weight;a+=l,i.soft.sidebarEvent={hits:S,score:l}}}if(r.soft.devTools){var f=n.keyboardShortcuts.filter(function(F){return F.t>=e.startTime&&F.t<=p}).length;if(f>0){var g=r.soft.devTools.weight;a+=g,i.soft.devTools={hits:f,score:g}}}if(r.soft.foreignInput&&e.foreignInputEvents.length>0){var I=e.foreignInputEvents.length,D=r.soft.foreignInput.weight;a+=D,i.soft.foreignInput={hits:I,score:D}}for(var P={},L=Object.keys(r.hard),j=0;j<L.length;j++){var C=L[j],K=C==="paste"?n.pasteCount:C==="copy"?n.copyCount:C==="drop"?n.dropCount:0;P[C]={count:K,threshold:r.hard[C].countThreshold,triggered:K>=r.hard[C].countThreshold}}return{trialSoftScore:a,trialSignals:i,updatedHardScore:P}}function ne(e,n){if(!n.screenout.enabled)return!1;var t=Object.keys(e.hardScore).some(function(o){return e.hardScore[o].triggered});return t?!0:e.trialsCompleted<n.screenout.gracePeriodTrials?!1:e.softScore>=n.scoring.softScoreThreshold}function oe(e){var n=e.config,t=e.trialData;n.signals.paste&&e.addTrialListener(document,"paste",function(o){var r="";try{r=(o.clipboardData||window.clipboardData).getData("text")}catch{}var i=r.length;if(i>=n.thresholds.pasteMinChars){var a=e.isKnownInput(o.target),c={type:"paste",t:performance.now(),pastedLength:i,isKnownInput:a};n.collectForPostHoc.pasteDropContent&&(c.text=r),t.pasteEvents.push(c),e.sessionData.pasteCount++,e.fireSignal("paste",o,{pastedLength:i,isKnownInput:a,text:r})}}),n.signals.copy&&(e.addTrialListener(document,"copy",function(o){var r=window.getSelection(),i=r?r.toString():"",a=i.length;t.copyEvents.push({type:"copy",t:performance.now(),selectedLength:a}),e.sessionData.copyCount++,e.fireSignal("copy",o,{selectedLength:a})}),e.addTrialListener(document,"cut",function(o){t.copyEvents.push({type:"cut",t:performance.now()}),e.sessionData.copyCount++,e.fireSignal("cut",o,{})})),n.signals.drop&&e.addTrialListener(document,"drop",function(o){var r="";try{r=o.dataTransfer.getData("text")}catch{}var i=r.length;if(i>=n.thresholds.dropMinChars){var a=e.isKnownInput(o.target),c={type:"drop",t:performance.now(),droppedLength:i,isKnownInput:a};n.collectForPostHoc.pasteDropContent&&(c.text=r),t.dropEvents.push(c),e.sessionData.dropCount++,e.fireSignal("drop",o,{droppedLength:i,isKnownInput:a,text:r})}})}function ae(e){var n=e.config;if(n.signals.tabAway){let r=function(a){t===null&&(t=performance.now(),o=a,e.fireSignal("tabAway",null,{type:a}))},i=function(){if(t!==null){var a=performance.now()-t,c={start:t,duration_ms:Math.round(a),type:o,timestamp:new Date(Date.now()-a).toISOString()};e.getTrialData()&&e.getTrialData().tabAwayEvents.push(c),e.sessionData.tabAwayEvents.push(c),e.sessionData.tabAwaySums.push(Math.round(a)),e.fireSignal("tabReturn",null,{duration_ms:Math.round(a),type:o}),t=null,o=null}};var t=null,o=null;e.addListener(document,"visibilitychange",function(){document.hidden?r("tabHidden"):i()}),e.addListener(window,"blur",function(){r("windowBlur")}),e.addListener(window,"focus",function(){document.hidden||i()})}}function ie(e){var n=e.config,t=e.trialData;if(n.signals.idleGaps){var o=n.thresholds.idleGapMs,r=performance.now();e.addTrialListener(document,"keydown",function(){r=performance.now()}),e.addTrialListener(document,"mousemove",function(){r=performance.now()},{passive:!0});var i=setInterval(function(){if(e.getTrialData()){var a=performance.now()-r;a>o&&(t.idleGaps.push({duration_ms:Math.round(a),t:performance.now()}),r=performance.now())}},n.thresholds.idleCheckIntervalMs);e.addTrialInterval(i)}}function se(e){var n=e.config,t=e.trialData;if(n.signals.mouseTracking){let c=function(v){return function(d){t.mouseEvents.length>=r||t.mouseEvents.push({x:Math.round(d.pageX),y:Math.round(d.pageY),t:Math.round(performance.now()-a),type:v})}};var o=n.thresholds.mouseThrottleMs,r=n.thresholds.mouseMaxEvents,i=0,a=t.startTime;t.mouseTrackingCapped=!1,t.mouseTrackingCappedAtMs=null,e.addTrialListener(document,"mousemove",function(v){if(t.mouseEvents.length>=r){t.mouseTrackingCapped||(t.mouseTrackingCapped=!0,t.mouseTrackingCappedAtMs=Math.round(performance.now()-a));return}var d=performance.now();d-i<o||(i=d,t.mouseEvents.push({x:Math.round(v.pageX),y:Math.round(v.pageY),t:Math.round(d-a),type:"move"}))},{passive:!0}),e.addTrialListener(document,"click",c("click"),{passive:!0}),e.addTrialListener(document,"mousedown",c("down"),{passive:!0}),e.addTrialListener(document,"mouseup",c("up"),{passive:!0})}}function le(e,n){var t=e.filter(function(g){return g.type==="move"});if(t.length<n)return null;for(var o=0,r=[],i=0,a=0,c=0,v=0,d=1;d<t.length;d++){var h=t[d].x-t[d-1].x,m=t[d].y-t[d-1].y,T=Math.sqrt(h*h+m*m);o+=T;var y=t[d].t-t[d-1].t;y>0&&r.push(T/y),d>1&&((h>0&&c<0||h<0&&c>0)&&i++,(m>0&&v<0||m<0&&v>0)&&a++),c=h,v=m}for(var k=t[0],M=t[t.length-1],b=Math.sqrt(Math.pow(M.x-k.x,2)+Math.pow(M.y-k.y,2)),E=o>0?Math.round(b/o*1e3)/1e3:0,u=0,p=0,S=0;S<r.length;S++){var l=r[S]-u;u+=l/(S+1),p+=l*(r[S]-u)}var f=r.length>1?Math.round(p/(r.length-1)*1e4)/1e4:0;return{pathEfficiency:E,directionChanges:i+a,speedVariance:f,moveCount:t.length}}function ce(e){var n=e.config,t=e.trialData;if(n.signals.clipboardManager){var o=0;e.addTrialListener(document,"keydown",function(){o=performance.now()}),e.addTrialListener(document,"input",function(r){if(r.target&&(r.target.tagName==="INPUT"||r.target.tagName==="TEXTAREA"||r.target.isContentEditable)&&(t.editTimestamps.push(performance.now()),performance.now()-o>n.thresholds.syntheticGapMs&&r.inputType==="insertText")){var i=(r.data||"").length;t.syntheticInsertions.push({type:"synthetic_insertion",t:performance.now(),dataLength:i}),e.fireSignal("syntheticInsertion",r,{dataLength:i})}},!0)}n.signals.typingSpeed&&!n.signals.clipboardManager&&e.addTrialListener(document,"input",function(r){r.target&&(r.target.tagName==="INPUT"||r.target.tagName==="TEXTAREA"||r.target.isContentEditable)&&t.editTimestamps.push(performance.now())},!0)}function ue(e){var n=e.config,t=e.trialData;e.addTrialListener(document,"input",function(o){var r=o.target;if(r){var i=r.tagName==="INPUT"||r.tagName==="TEXTAREA"||r.isContentEditable;if(i){var a=e.isKnownInput(r);if(a===!1){var c={t:performance.now(),targetTag:r.tagName||"unknown",targetId:(r.id||"").slice(0,50),targetClass:(r.className||"").toString().slice(0,100),inputType:o.inputType||""};n.collectForPostHoc.foreignInputContent&&(c.data=o.data||""),t.foreignInputEvents.push(c),e.fireSignal("typingOutsideExperiment",o,{targetTag:c.targetTag,targetId:c.targetId,targetClass:c.targetClass,data:o.data||""})}}}},!0)}function de(e){if(e.length<2)return null;var n=e[0],t=e[e.length-1],o=(t-n)/1e3;if(o<=0)return null;var r=e.length;return Math.round(r/o*10)/10}function pe(e){var n=e.config,t=e.sessionData;if(n.signals.sidebarGap){var o=window.devicePixelRatio||1,r=window.innerWidth,i=!1,a=null,c=null,v=0,d=null,h=!1,m=null;e.addInterval(setInterval(function(){var l=window.innerWidth,f=n.thresholds.sidebarGapPx,g=r-l;if(!i&&g>f)i=!0,a=performance.now(),c="innerWidth_delta",v=g,d=l,t.sidebarEvents.push({type:"opened",method:"innerWidth_delta",deltaIW:g,innerWidth:l,baselineIW:r,t:performance.now()}),e.fireSignal("sidebarOpened",null,{deltaIW:g});else if(i&&c==="innerWidth_delta"&&g<f/2){var I=performance.now()-a,D=d!=null?d-l:null;t.sidebarEvents.push({type:"closed",method:"innerWidth_delta",deltaIW:D,duration_ms:Math.round(I),t:performance.now()}),e.fireSignal("sidebarClosed",null,{duration_ms:Math.round(I),deltaIW:D}),i=!1,a=null,d=null,r=l}else i||(r=l);var P=l-document.documentElement.clientWidth,L=n.thresholds.layoutCompressionPx;if(!h&&P>L)h=!0,m=performance.now(),t.sidebarEvents.push({type:"opened",method:"layout_compression",gap:P,t:performance.now()});else if(h&&P<=L){var j=performance.now()-m;t.sidebarEvents.push({type:"closed",method:"layout_compression",duration_ms:Math.round(j),t:performance.now()}),h=!1,m=null}var C=window.devicePixelRatio||1;C!==o&&(t.zoomChanges.push({from:o,to:C,t:performance.now()}),r=l,o=C)},n.thresholds.sidebarPollMs))}if(n.signals.aiExtensions){let l=function(){X.forEach(function(f){if(document.querySelector(f.sel)){var g=t.aiExtensionsFound.some(function(I){return I.name===f.name});g||t.aiExtensionsFound.push({name:f.name,t:performance.now()})}})};l(),e.addInterval(setInterval(l,n.thresholds.extensionScanMs))}if((n.signals.keyboardShortcuts||n.signals.devTools)&&e.addListener(document,"keydown",function(l){var f=l.ctrlKey||l.metaKey;if(f&&l.shiftKey&&(l.key==="I"||l.key==="J"||l.key==="C")){var g="Ctrl+Shift+"+l.key;t.keyboardShortcuts.push({combo:g,t:performance.now()}),e.fireSignal("keyboardShortcut",l,{combo:g})}l.key==="F12"&&(t.keyboardShortcuts.push({combo:"F12",t:performance.now()}),e.fireSignal("keyboardShortcut",l,{combo:"F12"}))}),n.signals.windowPosition&&n.collectForPostHoc.windowPositionLog){var T=function(){t.windowPositions.push({x:window.screenX,y:window.screenY,w:window.outerWidth,h:window.outerHeight,iw:window.innerWidth,ih:window.innerHeight,sw:window.screen.width,sh:window.screen.height,dpr:window.devicePixelRatio,vvScale:window.visualViewport?window.visualViewport.scale:null,t:performance.now()})};e.addInterval(setInterval(T,n.thresholds.windowPositionPollMs));var y=null,k=function(){y&&clearTimeout(y),y=setTimeout(function(){T(),y=null},250)};e.addListener(window,"resize",k)}if(n.signals.aiExtensions){let l=function(f){var g=f.toLowerCase();return Y.some(function(I){return g.indexOf(I)!==-1})};var M=new MutationObserver(function(f){for(var g=0;g<f.length;g++)for(var I=f[g].addedNodes,D=0;D<I.length;D++){var P=I[D];if(P.nodeType===Node.ELEMENT_NODE){var L=P.tagName||"";L.indexOf("-")!==-1&&!l(L)&&t.extensionInjections.push({tag:L.toLowerCase(),hasShadow:!!P.shadowRoot,t:performance.now()})}}});M.observe(document.body,{childList:!0,subtree:!1}),e.listeners.push({target:null,event:"mutation",handler:M,options:{_isMutationObserver:!0}})}if(n.signals.sidebarGap){var b=document.documentElement.clientWidth,E=null,u=null,p=function(){if(u=null,E!==null){var l=E;E=null;var f=b-l;Math.abs(f)>n.thresholds.layoutCompressionPx&&(t.viewportWidthShifts.push({oldWidth:Math.round(b),newWidth:Math.round(l),delta:Math.round(f),t:performance.now()}),b=l)}},S=new ResizeObserver(function(l){for(var f=0;f<l.length;f++)E=l[f].contentRect.width;u&&clearTimeout(u),u=setTimeout(p,n.thresholds.viewportShiftDebounceMs),e.addInterval(u)});S.observe(document.documentElement),e.listeners.push({target:null,event:"resize",handler:S,options:{_isResizeObserver:!0}})}}function fe(e){var n=e.config,t=e.trialData;if(n.collectForPostHoc.elementTrace){t.elementTrace=[];var o=0,r=0;e.addTrialListener(document,"mousemove",function(a){o=a.clientX,r=a.clientY},{passive:!0});var i=setInterval(function(){if(e.getTrialData()&&!(o===0&&r===0))try{var a=document.elementsFromPoint(o,r);if(a&&a.length>0){var c=a[0];t.elementTrace.push({tag:c.tagName.toLowerCase(),id:c.id||null,t:Math.round(performance.now()-t.startTime)})}}catch{}},n.thresholds.elementTraceHz);e.addTrialInterval(i)}}function R(e,n,t,o){return t==="C"?e:n==="calibration-metadata"?"Validation trial (integrity check, ID: cal-"+o+`).
|
|
1
|
+
// cyborg-hunter v0.9.1 — https://github.com/cyborg-hunter/cyborg-hunter
|
|
2
|
+
var CyborgHunter=(()=>{var _=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var Ee=Object.prototype.hasOwnProperty;var Ie=(e,n)=>{for(var t in n)_(e,t,{get:n[t],enumerable:!0})},Me=(e,n,t,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of be(n))!Ee.call(e,r)&&r!==t&&_(e,r,{get:()=>n[r],enumerable:!(o=Te(n,r))||o.enumerable});return e};var xe=e=>Me(_({},"__esModule",{value:!0}),e);var Fe={};Ie(Fe,{VERSION:()=>q,addHoneypot:()=>me,init:()=>we,preventTextSelection:()=>ve,setAltText:()=>ye});var W={created:["session","destroyed"],session:["trial","destroyed"],trial:["session","destroyed"],destroyed:[]};function J(){let e="created";return{get current(){return e},transition(n){return W[e]&&W[e].indexOf(n)!==-1?(e=n,!0):(console.warn("[cyborg-hunter] invalid transition: "+e+" \u2192 "+n),!1)}}}function N(e){if(e===null||typeof e!="object")return e;try{return JSON.parse(JSON.stringify(e))}catch{return e}}var q="0.9.1",z={pasteMinChars:0,dropMinChars:0,sidebarGapPx:100,layoutCompressionPx:20,viewportShiftDebounceMs:250,syntheticGapMs:100,idleGapMs:1e4,idleCheckIntervalMs:5e3,mouseThrottleMs:50,mouseMaxEvents:2e3,mouseBotMinEvents:3,sidebarPollMs:2e3,extensionScanMs:3e4,windowPositionPollMs:2e3,elementTraceHz:500,tabAwayDurationMs:3e3,typingSpeedCps:10},$={permissive:{signals:{paste:!0,copy:!0,drop:!0,tabAway:!0,typingSpeed:!0,devTools:!0,aiExtensions:!0,sidebarGap:!0,keyboardShortcuts:!0,mouseTracking:!0,idleGaps:!0,windowPosition:!0,clipboardManager:!0,keystrokeDynamics:!1},thresholds:{typingSpeedCps:15},scoring:{hard:{paste:{countThreshold:3},drop:{countThreshold:3}},soft:{copy:{weight:1,maxPerTrial:2},tabAway:{weight:1,maxPerTrial:2},typingSpeed:{weight:1},sidebarEvent:{weight:1},devTools:{weight:1},foreignInput:{weight:1}},softScoreThreshold:10},screenout:{enabled:!1,gracePeriodTrials:5}},standard:{signals:{paste:!0,copy:!0,drop:!0,tabAway:!0,typingSpeed:!0,devTools:!0,aiExtensions:!0,sidebarGap:!0,keyboardShortcuts:!0,mouseTracking:!0,idleGaps:!0,windowPosition:!0,clipboardManager:!0,keystrokeDynamics:!1},thresholds:{},scoring:{hard:{paste:{countThreshold:2},drop:{countThreshold:2}},soft:{copy:{weight:2,maxPerTrial:2},tabAway:{weight:1,maxPerTrial:2},typingSpeed:{weight:2},sidebarEvent:{weight:3},devTools:{weight:1},foreignInput:{weight:2}},softScoreThreshold:6},screenout:{enabled:!0,gracePeriodTrials:3}},strict:{signals:{paste:!0,copy:!0,drop:!0,tabAway:!0,typingSpeed:!0,devTools:!0,aiExtensions:!0,sidebarGap:!0,keyboardShortcuts:!0,mouseTracking:!0,idleGaps:!0,windowPosition:!0,clipboardManager:!0,keystrokeDynamics:!0},thresholds:{typingSpeedCps:8,tabAwayDurationMs:5e3,mouseMaxEvents:5e3},scoring:{hard:{paste:{countThreshold:1},copy:{countThreshold:2},drop:{countThreshold:1}},soft:{tabAway:{weight:2,maxPerTrial:1},typingSpeed:{weight:3},sidebarEvent:{weight:2},devTools:{weight:2},foreignInput:{weight:3}},softScoreThreshold:4},screenout:{enabled:!0,gracePeriodTrials:2}}},X=[{name:"ChatGPT sidebar",sel:"chatgpt-sidebar"},{name:"ChatGPT extension",sel:"[data-chatgpt]"},{name:"Copilot extension",sel:"copilot-suggestions"},{name:"Copilot extension",sel:"[data-copilot]"},{name:"Gemini extension",sel:"gemini-panel"},{name:"Claude extension",sel:"[data-claude-extension]"},{name:"Monica AI",sel:"monica-root"},{name:"Merlin AI",sel:"merlin-root"},{name:"Sider AI",sel:"[data-sider-extension]"},{name:"MaxAI",sel:"[data-maxai]"},{name:"AI assistant",sel:"[data-ai-assistant]"},{name:"AI iframe (OpenAI)",sel:'iframe[src*="chat.openai.com"]'},{name:"AI iframe (Copilot)",sel:'iframe[src*="copilot.microsoft.com"]'},{name:"AI iframe (Gemini)",sel:'iframe[src*="gemini.google.com"]'},{name:"AI iframe (Claude)",sel:'iframe[src*="claude.ai"]'},{name:"AI iframe (Perplexity)",sel:'iframe[src*="perplexity.ai"]'}],Y=["grammarly","lastpass","1password","bitwarden","dashlane","roboform","honey","ublock","adblock"];var Q={dataDir:"./data",replayDir:null,scoreWeights:null,filePattern:"*.json",participantIdField:"participantId",trialIdField:"trialId",trialOrderField:"trialIndex",integrityField:"integrity",sessionIntegrityPath:null,trialsPerParticipant:null,platformIdField:null,showPlatformId:!1,conditionField:null,groupField:null,typingSpeedThreshold_cps:10,tabAwayMinDuration_ms:3e3,idleGapThreshold_ms:1e4,suspiciouslyFastRT_ms:2e3,scoring:null,signals:null,phaseScope:null,trajectoryGrid:"auto",trajectoryTrialLabel:"trialId",trajectoryResponseField:null,trajectoryDisplayOrder:"rule",outputDir:"./cyborg-hunter-report",outputFormat:"html"};var Ce=["replayDir",...Object.keys(Q),...Object.keys(z),"preset","participantId","signals","thresholds","scoring","domProtection","collectForPostHoc","onSignal","screenout","experimentContainer","knownInputs","decoyAnswers","decoyMap","decoyVisibility","decoyFraming","decoyExcludeButtons","autoMonitor","excludeTrialTypes"];function ee(e,n=Ce){let t=[];return Object.keys(e).forEach(o=>{if(!n.includes(o)){let r=Ae(o,n),i=r?`Unknown config key "${o}" \u2014 did you mean "${r}"?`:`Unknown config key "${o}"`;t.push(i)}}),t}function te(e){let n=[];if(!e||typeof e!="object")return n;let t=e.hard||{};Object.keys(t).forEach(r=>{let i=t[r];(!i||!Number.isFinite(i.countThreshold))&&n.push(`scoring.hard.${r} has no finite numeric countThreshold (got ${i?Z(i.countThreshold):"no rule"}) \u2014 this hard screenout rule can never trigger. A likely cause is a typo in the override key (e.g. "countThreshhold").`)});let o=e.soft||{};return Object.keys(o).forEach(r=>{let i=o[r];(!i||!Number.isFinite(i.weight))&&n.push(`scoring.soft.${r} has no finite numeric weight (got ${i?Z(i.weight):"no rule"}) \u2014 this soft signal contributes nothing (or breaks the soft score). A likely cause is a typo in the override key (e.g. "wieght").`)}),n}function Z(e){try{return String(e)}catch{return typeof e}}function Ae(e,n){let t=null,o=1/0;for(let r of n){let i=Pe(e.toLowerCase(),r.toLowerCase());i<o&&i<=3&&(o=i,t=r)}return t}function Pe(e,n){let t=e.length,o=n.length,r=Array.from({length:t+1},()=>Array(o+1).fill(0));for(let i=0;i<=t;i++)r[i][0]=i;for(let i=0;i<=o;i++)r[0][i]=i;for(let i=1;i<=t;i++)for(let a=1;a<=o;a++)r[i][a]=e[i-1]===n[a-1]?r[i-1][a-1]:1+Math.min(r[i-1][a],r[i][a-1],r[i-1][a-1]);return r[t][o]}function re(e,n,t,o){var r=t.scoring,i={hard:{},soft:{}},a=0;if(r.hard.paste){var c=(e.pasteEvents||[]).length;i.hard.paste={trialHits:c,sessionTotal:n.pasteCount,countThreshold:r.hard.paste.countThreshold}}if(r.hard.copy){var v=(e.copyEvents||[]).length;i.hard.copy={trialHits:v,sessionTotal:n.copyCount,countThreshold:r.hard.copy.countThreshold}}if(r.hard.drop){var d=(e.dropEvents||[]).length;i.hard.drop={trialHits:d,sessionTotal:n.dropCount,countThreshold:r.hard.drop.countThreshold}}if(r.soft.copy){var h=(e.copyEvents||[]).length,m=r.soft.copy.maxPerTrial!=null?Math.min(h,r.soft.copy.maxPerTrial):h,T=m*r.soft.copy.weight;a+=T,i.soft.copy={hits:h,capped:m,score:T}}if(r.soft.tabAway){var y=(e.tabAwayEvents||[]).filter(function(F){return(F.duration_ms||0)>t.thresholds.tabAwayDurationMs}).length,k=r.soft.tabAway.maxPerTrial!=null?Math.min(y,r.soft.tabAway.maxPerTrial):y,M=k*r.soft.tabAway.weight;a+=M,i.soft.tabAway={hits:y,capped:k,score:M}}if(r.soft.typingSpeed&&o.charsPerSec!=null){var b=t.thresholds.typingSpeedCps,E=o.charsPerSec>b?1:0,u=E*r.soft.typingSpeed.weight;a+=u,i.soft.typingSpeed={charsPerSec:o.charsPerSec,threshold:b,hit:E,score:u}}var p=e.startTime+(o&&o.duration_ms!=null?o.duration_ms:performance.now()-e.startTime);if(r.soft.sidebarEvent){var S=n.sidebarEvents.filter(function(F){return F.t>=e.startTime&&F.t<=p}).length;if(S>0){var l=r.soft.sidebarEvent.weight;a+=l,i.soft.sidebarEvent={hits:S,score:l}}}if(r.soft.devTools){var f=n.keyboardShortcuts.filter(function(F){return F.t>=e.startTime&&F.t<=p}).length;if(f>0){var g=r.soft.devTools.weight;a+=g,i.soft.devTools={hits:f,score:g}}}if(r.soft.foreignInput&&e.foreignInputEvents.length>0){var I=e.foreignInputEvents.length,D=r.soft.foreignInput.weight;a+=D,i.soft.foreignInput={hits:I,score:D}}for(var P={},L=Object.keys(r.hard),j=0;j<L.length;j++){var C=L[j],K=C==="paste"?n.pasteCount:C==="copy"?n.copyCount:C==="drop"?n.dropCount:0;P[C]={count:K,threshold:r.hard[C].countThreshold,triggered:K>=r.hard[C].countThreshold}}return{trialSoftScore:a,trialSignals:i,updatedHardScore:P}}function ne(e,n){if(!n.screenout.enabled)return!1;var t=Object.keys(e.hardScore).some(function(o){return e.hardScore[o].triggered});return t?!0:e.trialsCompleted<n.screenout.gracePeriodTrials?!1:e.softScore>=n.scoring.softScoreThreshold}function oe(e){var n=e.config,t=e.trialData;n.signals.paste&&e.addTrialListener(document,"paste",function(o){var r="";try{r=(o.clipboardData||window.clipboardData).getData("text")}catch{}var i=r.length;if(i>=n.thresholds.pasteMinChars){var a=e.isKnownInput(o.target),c={type:"paste",t:performance.now(),pastedLength:i,isKnownInput:a};n.collectForPostHoc.pasteDropContent&&(c.text=r),t.pasteEvents.push(c),e.sessionData.pasteCount++,e.fireSignal("paste",o,{pastedLength:i,isKnownInput:a,text:r})}}),n.signals.copy&&(e.addTrialListener(document,"copy",function(o){var r=window.getSelection(),i=r?r.toString():"",a=i.length;t.copyEvents.push({type:"copy",t:performance.now(),selectedLength:a}),e.sessionData.copyCount++,e.fireSignal("copy",o,{selectedLength:a})}),e.addTrialListener(document,"cut",function(o){t.copyEvents.push({type:"cut",t:performance.now()}),e.sessionData.copyCount++,e.fireSignal("cut",o,{})})),n.signals.drop&&e.addTrialListener(document,"drop",function(o){var r="";try{r=o.dataTransfer.getData("text")}catch{}var i=r.length;if(i>=n.thresholds.dropMinChars){var a=e.isKnownInput(o.target),c={type:"drop",t:performance.now(),droppedLength:i,isKnownInput:a};n.collectForPostHoc.pasteDropContent&&(c.text=r),t.dropEvents.push(c),e.sessionData.dropCount++,e.fireSignal("drop",o,{droppedLength:i,isKnownInput:a,text:r})}})}function ae(e){var n=e.config;if(n.signals.tabAway){let r=function(a){t===null&&(t=performance.now(),o=a,e.fireSignal("tabAway",null,{type:a}))},i=function(){if(t!==null){var a=performance.now()-t,c={start:t,duration_ms:Math.round(a),type:o,timestamp:new Date(Date.now()-a).toISOString()};e.getTrialData()&&e.getTrialData().tabAwayEvents.push(c),e.sessionData.tabAwayEvents.push(c),e.sessionData.tabAwaySums.push(Math.round(a)),e.fireSignal("tabReturn",null,{duration_ms:Math.round(a),type:o}),t=null,o=null}};var t=null,o=null;e.addListener(document,"visibilitychange",function(){document.hidden?r("tabHidden"):i()}),e.addListener(window,"blur",function(){r("windowBlur")}),e.addListener(window,"focus",function(){document.hidden||i()})}}function ie(e){var n=e.config,t=e.trialData;if(n.signals.idleGaps){var o=n.thresholds.idleGapMs,r=performance.now();e.addTrialListener(document,"keydown",function(){r=performance.now()}),e.addTrialListener(document,"mousemove",function(){r=performance.now()},{passive:!0});var i=setInterval(function(){if(e.getTrialData()){var a=performance.now()-r;a>o&&(t.idleGaps.push({duration_ms:Math.round(a),t:performance.now()}),r=performance.now())}},n.thresholds.idleCheckIntervalMs);e.addTrialInterval(i)}}function se(e){var n=e.config,t=e.trialData;if(n.signals.mouseTracking){let c=function(v){return function(d){t.mouseEvents.length>=r||t.mouseEvents.push({x:Math.round(d.pageX),y:Math.round(d.pageY),t:Math.round(performance.now()-a),type:v})}};var o=n.thresholds.mouseThrottleMs,r=n.thresholds.mouseMaxEvents,i=0,a=t.startTime;t.mouseTrackingCapped=!1,t.mouseTrackingCappedAtMs=null,e.addTrialListener(document,"mousemove",function(v){if(t.mouseEvents.length>=r){t.mouseTrackingCapped||(t.mouseTrackingCapped=!0,t.mouseTrackingCappedAtMs=Math.round(performance.now()-a));return}var d=performance.now();d-i<o||(i=d,t.mouseEvents.push({x:Math.round(v.pageX),y:Math.round(v.pageY),t:Math.round(d-a),type:"move"}))},{passive:!0}),e.addTrialListener(document,"click",c("click"),{passive:!0}),e.addTrialListener(document,"mousedown",c("down"),{passive:!0}),e.addTrialListener(document,"mouseup",c("up"),{passive:!0})}}function le(e,n){var t=e.filter(function(g){return g.type==="move"});if(t.length<n)return null;for(var o=0,r=[],i=0,a=0,c=0,v=0,d=1;d<t.length;d++){var h=t[d].x-t[d-1].x,m=t[d].y-t[d-1].y,T=Math.sqrt(h*h+m*m);o+=T;var y=t[d].t-t[d-1].t;y>0&&r.push(T/y),d>1&&((h>0&&c<0||h<0&&c>0)&&i++,(m>0&&v<0||m<0&&v>0)&&a++),c=h,v=m}for(var k=t[0],M=t[t.length-1],b=Math.sqrt(Math.pow(M.x-k.x,2)+Math.pow(M.y-k.y,2)),E=o>0?Math.round(b/o*1e3)/1e3:0,u=0,p=0,S=0;S<r.length;S++){var l=r[S]-u;u+=l/(S+1),p+=l*(r[S]-u)}var f=r.length>1?Math.round(p/(r.length-1)*1e4)/1e4:0;return{pathEfficiency:E,directionChanges:i+a,speedVariance:f,moveCount:t.length}}function ce(e){var n=e.config,t=e.trialData;if(n.signals.clipboardManager){var o=0;e.addTrialListener(document,"keydown",function(){o=performance.now()}),e.addTrialListener(document,"input",function(r){if(r.target&&(r.target.tagName==="INPUT"||r.target.tagName==="TEXTAREA"||r.target.isContentEditable)&&(t.editTimestamps.push(performance.now()),performance.now()-o>n.thresholds.syntheticGapMs&&r.inputType==="insertText")){var i=(r.data||"").length;t.syntheticInsertions.push({type:"synthetic_insertion",t:performance.now(),dataLength:i}),e.fireSignal("syntheticInsertion",r,{dataLength:i})}},!0)}n.signals.typingSpeed&&!n.signals.clipboardManager&&e.addTrialListener(document,"input",function(r){r.target&&(r.target.tagName==="INPUT"||r.target.tagName==="TEXTAREA"||r.target.isContentEditable)&&t.editTimestamps.push(performance.now())},!0)}function ue(e){var n=e.config,t=e.trialData;e.addTrialListener(document,"input",function(o){var r=o.target;if(r){var i=r.tagName==="INPUT"||r.tagName==="TEXTAREA"||r.isContentEditable;if(i){var a=e.isKnownInput(r);if(a===!1){var c={t:performance.now(),targetTag:r.tagName||"unknown",targetId:(r.id||"").slice(0,50),targetClass:(r.className||"").toString().slice(0,100),inputType:o.inputType||""};n.collectForPostHoc.foreignInputContent&&(c.data=o.data||""),t.foreignInputEvents.push(c),e.fireSignal("typingOutsideExperiment",o,{targetTag:c.targetTag,targetId:c.targetId,targetClass:c.targetClass,data:o.data||""})}}}},!0)}function de(e){if(e.length<2)return null;var n=e[0],t=e[e.length-1],o=(t-n)/1e3;if(o<=0)return null;var r=e.length;return Math.round(r/o*10)/10}function pe(e){var n=e.config,t=e.sessionData;if(n.signals.sidebarGap){var o=window.devicePixelRatio||1,r=window.innerWidth,i=!1,a=null,c=null,v=0,d=null,h=!1,m=null;e.addInterval(setInterval(function(){var l=window.innerWidth,f=n.thresholds.sidebarGapPx,g=r-l;if(!i&&g>f)i=!0,a=performance.now(),c="innerWidth_delta",v=g,d=l,t.sidebarEvents.push({type:"opened",method:"innerWidth_delta",deltaIW:g,innerWidth:l,baselineIW:r,t:performance.now()}),e.fireSignal("sidebarOpened",null,{deltaIW:g});else if(i&&c==="innerWidth_delta"&&g<f/2){var I=performance.now()-a,D=d!=null?d-l:null;t.sidebarEvents.push({type:"closed",method:"innerWidth_delta",deltaIW:D,duration_ms:Math.round(I),t:performance.now()}),e.fireSignal("sidebarClosed",null,{duration_ms:Math.round(I),deltaIW:D}),i=!1,a=null,d=null,r=l}else i||(r=l);var P=l-document.documentElement.clientWidth,L=n.thresholds.layoutCompressionPx;if(!h&&P>L)h=!0,m=performance.now(),t.sidebarEvents.push({type:"opened",method:"layout_compression",gap:P,t:performance.now()});else if(h&&P<=L){var j=performance.now()-m;t.sidebarEvents.push({type:"closed",method:"layout_compression",duration_ms:Math.round(j),t:performance.now()}),h=!1,m=null}var C=window.devicePixelRatio||1;C!==o&&(t.zoomChanges.push({from:o,to:C,t:performance.now()}),r=l,o=C)},n.thresholds.sidebarPollMs))}if(n.signals.aiExtensions){let l=function(){X.forEach(function(f){if(document.querySelector(f.sel)){var g=t.aiExtensionsFound.some(function(I){return I.name===f.name});g||t.aiExtensionsFound.push({name:f.name,t:performance.now()})}})};l(),e.addInterval(setInterval(l,n.thresholds.extensionScanMs))}if((n.signals.keyboardShortcuts||n.signals.devTools)&&e.addListener(document,"keydown",function(l){var f=l.ctrlKey||l.metaKey;if(f&&l.shiftKey&&(l.key==="I"||l.key==="J"||l.key==="C")){var g="Ctrl+Shift+"+l.key;t.keyboardShortcuts.push({combo:g,t:performance.now()}),e.fireSignal("keyboardShortcut",l,{combo:g})}l.key==="F12"&&(t.keyboardShortcuts.push({combo:"F12",t:performance.now()}),e.fireSignal("keyboardShortcut",l,{combo:"F12"}))}),n.signals.windowPosition&&n.collectForPostHoc.windowPositionLog){var T=function(){t.windowPositions.push({x:window.screenX,y:window.screenY,w:window.outerWidth,h:window.outerHeight,iw:window.innerWidth,ih:window.innerHeight,sw:window.screen.width,sh:window.screen.height,dpr:window.devicePixelRatio,vvScale:window.visualViewport?window.visualViewport.scale:null,t:performance.now()})};e.addInterval(setInterval(T,n.thresholds.windowPositionPollMs));var y=null,k=function(){y&&clearTimeout(y),y=setTimeout(function(){T(),y=null},250)};e.addListener(window,"resize",k)}if(n.signals.aiExtensions){let l=function(f){var g=f.toLowerCase();return Y.some(function(I){return g.indexOf(I)!==-1})};var M=new MutationObserver(function(f){for(var g=0;g<f.length;g++)for(var I=f[g].addedNodes,D=0;D<I.length;D++){var P=I[D];if(P.nodeType===Node.ELEMENT_NODE){var L=P.tagName||"";L.indexOf("-")!==-1&&!l(L)&&t.extensionInjections.push({tag:L.toLowerCase(),hasShadow:!!P.shadowRoot,t:performance.now()})}}});M.observe(document.body,{childList:!0,subtree:!1}),e.listeners.push({target:null,event:"mutation",handler:M,options:{_isMutationObserver:!0}})}if(n.signals.sidebarGap){var b=document.documentElement.clientWidth,E=null,u=null,p=function(){if(u=null,E!==null){var l=E;E=null;var f=b-l;Math.abs(f)>n.thresholds.layoutCompressionPx&&(t.viewportWidthShifts.push({oldWidth:Math.round(b),newWidth:Math.round(l),delta:Math.round(f),t:performance.now()}),b=l)}},S=new ResizeObserver(function(l){for(var f=0;f<l.length;f++)E=l[f].contentRect.width;u&&clearTimeout(u),u=setTimeout(p,n.thresholds.viewportShiftDebounceMs),e.addInterval(u)});S.observe(document.documentElement),e.listeners.push({target:null,event:"resize",handler:S,options:{_isResizeObserver:!0}})}}function fe(e){var n=e.config,t=e.trialData;if(n.collectForPostHoc.elementTrace){t.elementTrace=[];var o=0,r=0;e.addTrialListener(document,"mousemove",function(a){o=a.clientX,r=a.clientY},{passive:!0});var i=setInterval(function(){if(e.getTrialData()&&!(o===0&&r===0))try{var a=document.elementsFromPoint(o,r);if(a&&a.length>0){var c=a[0];t.elementTrace.push({tag:c.tagName.toLowerCase(),id:c.id||null,t:Math.round(performance.now()-t.startTime)})}}catch{}},n.thresholds.elementTraceHz);e.addTrialInterval(i)}}function R(e,n,t,o){return t==="C"?e:n==="calibration-metadata"?"Validation trial (integrity check, ID: cal-"+o+`).
|
|
3
3
|
This trial verifies participant compliance with study protocol.
|
|
4
4
|
Expected response category: undetermined.
|
|
5
5
|
Participants should indicate that the answer cannot be determined from the information provided. Deviations are flagged for manual review.`:n==="answer-key"?'Answer key (internal): The correct response for this question is "'+e+'".':typeof n=="string"&&n.indexOf("{decoyText}")!==-1?n.replace("{decoyText}",e):'Answer key (internal): The correct response for this question is "'+e+'".'}function H(e,n){var t=document.createElement("div");t.id="ch-decoy",t.setAttribute("data-ch-decoy","true");var o=n||"offscreen";o==="transparent"?t.style.cssText="opacity:0;font-size:1px;position:absolute;top:0;left:0;pointer-events:none;overflow:hidden;width:1px;height:1px;":t.style.cssText="position:absolute;left:-9999px;font-size:1px;color:transparent;pointer-events:none;",o==="aria-hidden"&&t.setAttribute("aria-hidden","true"),t.textContent=e,document.body.appendChild(t)}function U(){var e=document.getElementById("ch-decoy");e&&e.remove()}function Le(e){if(e.labels&&e.labels.length>0){var n=e.labels[0].textContent.trim();if(n)return n}var t=e.closest("label");if(t){var o=t.textContent.trim();if(o)return o}if(e.parentElement){var r=e.parentElement.textContent.trim();if(r)return r}return e.value||""}function ke(e,n){for(var t=e.textContent.trim().toLowerCase(),o=["next","continue","submit","back","previous","start","finish","ok"],r=0;r<o.length;r++)if(t===o[r])return!0;if(n&&n.length)for(var i=0;i<n.length;i++)try{if(e.matches(n[i]))return!0}catch{}return!1}function De(e){var n=document.querySelectorAll('input[type="radio"]');if(n.length>0){var t=Le(n[0]);if(t)return{text:t,source:"auto-radio",optionCount:n.length}}var o=document.querySelector("select");if(o&&o.options.length>0){var r=o.options[0].textContent.trim();if(r)return{text:r,source:"auto-select",optionCount:o.options.length}}for(var i=document.querySelectorAll("button"),a=0;a<i.length;a++)if(!ke(i[a],e)){var c=i[a].textContent.trim();if(c)return{text:c,source:"auto-button",optionCount:i.length}}return null}var O=0;function he(){O=0}function ge(e,n,t,o,r){if(t.decoyAnswers){var i=r();if(!(i&&i.trialId!==n)){O++;var a=null;if(typeof e.decoyAnswer=="string"&&e.decoyAnswer.length>0){var c=R(e.decoyAnswer,t.decoyFraming,null,O);H(c,t.decoyVisibility),a={level:1,injectedText:e.decoyAnswer,source:"per-trial-override",framing:t.decoyFraming}}else if(t.decoyMap&&t.decoyMap[n]){var v=t.decoyMap[n],d=typeof v=="string"?v:v.text,h=typeof v=="object"&&v.type?v.type:"unknown",m=R(d,t.decoyFraming,h,O);H(m,t.decoyVisibility),a={level:2,injectedText:d,type:h,source:"decoyMap",framing:t.decoyFraming}}else if(t.decoyMap){console.warn('[cyborg-hunter] no decoyMap entry for trialId "'+n+'". Falling back to Level 3/4.');var T=R(null,"calibration-metadata",null,O);H(T,t.decoyVisibility),a={level:4,injectedText:T,source:"calibration-fallback",framing:"calibration-metadata"}}else try{var y=De(t.decoyExcludeButtons);if(y){var k=R(y.text,t.decoyFraming,null,O);H(k,t.decoyVisibility),a={level:3,injectedText:y.text,source:y.source,optionCount:y.optionCount,framing:t.decoyFraming}}else{var M=R(null,"calibration-metadata",null,O);H(M,t.decoyVisibility),a={level:4,injectedText:M,source:"calibration-fallback",framing:"calibration-metadata"}}}catch{var b=R(null,"calibration-metadata",null,O);H(b,t.decoyVisibility),a={level:4,injectedText:b,source:"calibration-error",framing:"calibration-metadata"}}var E=r();E&&a&&(E.decoy=a)}}}function ve(e){for(var n=document.querySelectorAll(e),t=0;t<n.length;t++)n[t].style.userSelect="none",n[t].style.webkitUserSelect="none",n[t].style.msUserSelect="none"}function me(e,n){for(var t=document.querySelectorAll(e),o=0;o<t.length;o++){var r=document.createElement("span");r.textContent=n,r.setAttribute("data-honeypot","true"),r.style.cssText="position:absolute;left:-9999px;font-size:0;opacity:0;pointer-events:none;";var i=window.getComputedStyle(t[o]).position;i==="static"&&(t[o].style.position="relative"),t[o].appendChild(r)}}function ye(e,n){for(var t=document.querySelectorAll(e),o=0;o<t.length;o++)t[o].setAttribute("alt",n)}var V=null;function we(e){V&&(V.destroy(),V=null);var n=e.preset||"standard",t=$[n];if(!t)throw new Error("[cyborg-hunter] unknown preset '"+n+"'. Use: permissive, standard, strict.");var o=e.scoring||{},r=t.scoring,i={hard:Object.assign({},r.hard,o.hard||{}),soft:Object.assign({},r.soft,o.soft||{}),softScoreThreshold:o.softScoreThreshold!=null?o.softScoreThreshold:r.softScoreThreshold},a={participantId:e.participantId||"unknown",preset:n,signals:Object.assign({},t.signals,e.signals||{}),thresholds:Object.assign({},z,t.thresholds||{},e.thresholds||{}),scoring:i,screenout:Object.assign({},t.screenout,e.screenout||{}),domProtection:Object.assign({preventTextSelection:!1,honeypotText:null,logCopyAttempts:!0,renderStimulusAsCanvas:!1},e.domProtection||{}),collectForPostHoc:Object.assign({fullKeystrokeTimestamps:!1,rawMouseTrack:!0,responseText:!1,windowPositionLog:!0,elementTrace:!1,pasteDropContent:!0,foreignInputContent:!0},e.collectForPostHoc||{}),decoyAnswers:e.decoyAnswers||!1,decoyMap:e.decoyMap||null,decoyVisibility:e.decoyVisibility||"offscreen",decoyFraming:e.decoyFraming||"answer-key",decoyExcludeButtons:e.decoyExcludeButtons||[".jspsych-btn"]},c=["participantId","preset","signals","thresholds","scoring","screenout","domProtection","collectForPostHoc","decoyAnswers","decoyMap","decoyVisibility","decoyFraming","decoyExcludeButtons","onSignal","experimentContainer","knownInputs"],v=ee(e,c);v.forEach(function(s){console.warn("[cyborg-hunter] "+s)}),te(i).forEach(function(s){console.warn("[cyborg-hunter] "+s)}),Object.freeze(a),Object.freeze(a.signals),Object.freeze(a.thresholds),Object.freeze(a.scoring),Object.freeze(a.scoring.hard),Object.freeze(a.scoring.soft),Object.freeze(a.screenout);var d=typeof e.onSignal=="function"?e.onSignal:null,h=e.experimentContainer||null,m=null,T=e.knownInputs||null;function y(){return m||(h?(typeof h=="string"?m=document.querySelector(h):h.nodeType&&(m=h),m):null)}function k(s){if(!s)return!1;if(T)try{if(s.matches(T))return!0}catch{}var w=y();return w?w.contains(s):null}function M(s,w,x){if(d)try{d({type:s,event:w||null,trialId:p?p.trialId:null,data:x||{}})}catch{}}var b=J(),E=[],u={pasteCount:0,copyCount:0,dropCount:0,tabAwaySums:[],tabAwayEvents:[],charsPerSec:[],sidebarEvents:[],devToolsEvents:[],aiExtensionsFound:[],keyboardShortcuts:[],windowPositions:[],idleGaps:[],extensionInjections:[],viewportWidthShifts:E,layoutShifts:E,zoomChanges:[],hardScore:{},softScore:0,trialsCompleted:0},p=null,S=[],l=[],f=[],g=[];he();function I(s){if(!b.transition(s))throw new Error("[cyborg-hunter] invalid lifecycle call: cannot transition from '"+b.current+"' to '"+s+"'. Expected order: init() \u2192 startSession() \u2192 (startTrial \u2192 endTrial)* \u2192 destroy(). Common cause: a startTrial() without a preceding endTrial(), or a call after destroy().")}function D(s,w,x,A){s.addEventListener(w,x,A||!1),S.push({target:s,event:w,handler:x,options:A||!1})}function P(s,w,x,A){s.addEventListener(w,x,A||!1),l.push({target:s,event:w,handler:x,options:A||!1})}function L(s){f.push(s)}function j(s){g.push(s)}function C(){l.forEach(function(s){s.target.removeEventListener(s.event,s.handler,s.options)}),l=[],g.forEach(function(s){clearInterval(s)}),g=[],U()}function K(){return{config:a,sessionData:u,listeners:S,addListener:D,addInterval:L,fireSignal:M,getTrialData:function(){return p}}}function F(){return{config:a,sessionData:u,trialData:p,listeners:S,addTrialListener:P,addInterval:L,addTrialInterval:j,fireSignal:M,isKnownInput:k,getTrialData:function(){return p}}}var B={startSession:function(){I("session");var s=K();pe(s),ae(s)},startTrial:function(s){if(I("trial"),s=s||{},s.experimentContainer!=null&&(h=s.experimentContainer,m=null),s.knownInputs!=null&&(T=s.knownInputs),p={trialId:s.trialId||"trial-"+u.trialsCompleted,phase:s.phase||"default",startTime:performance.now(),pasteEvents:[],copyEvents:[],dropEvents:[],editTimestamps:[],mouseEvents:[],tabAwayEvents:[],idleGaps:[],foreignInputEvents:[],syntheticInsertions:[]},U(),!a.decoyAnswers)s.decoyAnswer!=null&&console.warn("[cyborg-hunter] decoyAnswer provided but decoyAnswers is not enabled. Add decoyAnswers: true to init() config.");else if(s.decoyAnswer===!1)p.decoy={level:0,source:"skipped"};else{var w=p.trialId,x=function(){ge(s,w,a,p,function(){return p})},A=typeof s.decoyAnswer=="string"&&s.decoyAnswer.length>0,Se=a.decoyMap&&a.decoyMap[w];A||Se?x():(s.decoyAnswer!=null&&console.warn("[cyborg-hunter] decoyAnswer must be a non-empty string, got: "+typeof s.decoyAnswer+". Falling through to auto-detection."),setTimeout(x,0))}var G=F();oe(G),ce(G),se(G),ie(G),fe(G),(h||T)&&ue(G)},endTrial:function(){if(I("session"),!p)return null;p.decoy&&(p.decoy.survivedTrial=!!document.getElementById("ch-decoy")),C();var s=N(p);s.duration_ms=performance.now()-p.startTime,s.libraryVersion=q,s.participantId=a.participantId,s.timestamp=new Date().toISOString();var w=de(p.editTimestamps);w!==null&&(s.charsPerSec=w,u.charsPerSec.push(w)),!a.signals.keystrokeDynamics&&!a.collectForPostHoc.fullKeystrokeTimestamps&&(s.editTimestamps=[]);var x=le(p.mouseEvents,a.thresholds.mouseBotMinEvents);x&&(s.mouseMetrics=x),a.collectForPostHoc.rawMouseTrack&&(s.mouseTrack=s.mouseEvents),delete s.mouseEvents,u.trialsCompleted++;var A=re(p,u,a,s);return s.trialSoftScore=A.trialSoftScore,s.trialSignals=A.trialSignals,u.softScore+=A.trialSoftScore,u.hardScore=A.updatedHardScore,p=null,s},getSessionScore:function(){return{hardScore:N(u.hardScore),softScore:u.softScore,softScoreThreshold:a.scoring.softScoreThreshold,anyHardTriggered:Object.keys(u.hardScore).some(function(s){return u.hardScore[s].triggered}),trialsCompleted:u.trialsCompleted}},getSessionReport:function(){var s=N(u);return s.hardScore=N(u.hardScore),s.softScore=u.softScore,s.softScoreThreshold=a.scoring.softScoreThreshold,s.anyHardTriggered=Object.keys(u.hardScore).some(function(w){return u.hardScore[w].triggered}),s.trialsCompleted=u.trialsCompleted,s.config={preset:a.preset,participantId:a.participantId,thresholds:{tabAwayDurationMs:a.thresholds.tabAwayDurationMs,typingSpeedCps:a.thresholds.typingSpeedCps}},s.libraryVersion=q,s},shouldScreenout:function(){return ne(u,a)},getRawData:function(){return N({session:u,config:{preset:a.preset,participantId:a.participantId},libraryVersion:q})},getTrialSnapshot:function(){return p?N(p):null},destroy:function(){b.transition("destroyed"),S.forEach(function(s){s.options&&s.options._isMutationObserver||s.options&&s.options._isResizeObserver?s.handler.disconnect():s.target.removeEventListener(s.event,s.handler,s.options)}),S=[],C(),f.forEach(function(s){clearInterval(s)}),f=[],V=null}};return Object.freeze(B),V=B,B}return xe(Fe);})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var n=class{static info={name:"cyborg-hunter",version:"0.9.
|
|
1
|
+
(()=>{var n=class{static info={name:"cyborg-hunter",version:"0.9.1",data:{integrity:{type:"object"}}};constructor(t){this.jsPsych=t,this.monitor=null,this.params={},this._monitoring=!1,this._trialStart_perfNow=null}initialize(t){this.params=t;let{autoMonitor:r,excludeTrialTypes:i,...e}=t,o=window.CyborgHunter||window.IntegrityMonitor;if(!o)throw new Error("CyborgHunter not found. Load cyborg-hunter.min.js before the jsPsych extension.");this.monitor=o.init(e),this.monitor.startSession()}on_start(t){}on_load(t){if(this._monitoring=!1,this.params.autoMonitor===!1&&!(t&&t.trialId))return;if(this.params.excludeTrialTypes){let i=this.jsPsych.getCurrentTrial().type?.info?.name||"";if(this.params.excludeTrialTypes.includes(i))return}this._monitoring=!0,this._trialStart_perfNow=performance.now();let r=this.jsPsych.getProgress().current_trial_global;this.monitor.startTrial({trialId:t&&t.trialId||`trial-${r}`,phase:t?.phase||null,decoyAnswer:t?.decoyAnswer??null,experimentContainer:t?.experimentContainer||null})}on_finish(t){if(!this._monitoring)return{};this._monitoring=!1;let r=this.monitor.endTrial();return r.trialStart_perfNow=this._trialStart_perfNow,this._trialStart_perfNow=null,{integrity:r}}finalize(){if(this.monitor){try{let t=this.monitor.getSessionReport(),{sidebarEvents:r=[],keyboardShortcuts:i=[],windowPositions:e=[],layoutShifts:o=[],zoomChanges:y=[],idleGaps:d=[],extensionInjections:u=[],tabAwaySums:g=[],charsPerSec:f=[],aiExtensionsFound:p=[],hardScore:m,softScore:s,anyHardTriggered:a,trialsCompleted:w,softScoreThreshold:_,pasteCount:h=0,copyCount:l=0,dropCount:c=0,libraryVersion:S,config:C,...b}=t;this.jsPsych.data.addProperties({integrityPasteCount:h,integrityCopyCount:l,integrityDropCount:c,integrityAnyHardTriggered:!!a,integritySoftScore:s,cyborgHunterVersion:S}),this.jsPsych.data.addDataToLastTrial({integritySession:{pasteCount:h,copyCount:l,dropCount:c,sidebarEvents:r,keyboardShortcuts:i,windowPositions:e,layoutShifts:o,zoomChanges:y,idleGaps:d,extensionInjections:u,tabAwaySums:g,charsPerSec:f,aiExtensionsFound:p,config:C,...b},integrityScore:{hardScore:m,softScore:s,anyHardTriggered:a,trialsCompleted:w,softScoreThreshold:_}})}catch(t){console.warn("[cyborg-hunter] Failed to save session report:",t);try{this.jsPsych.data.addProperties({cyborgHunterFinalizeError:String(t&&t.message?t.message:t)})}catch{}}this.monitor.destroy()}}};typeof window<"u"&&(window.jsPsychCyborgHunter=n);})();
|
package/package.json
CHANGED
package/src/cli/preview-entry.js
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
// is what this entry point bundles instead.
|
|
16
16
|
|
|
17
17
|
export { renderIndexHtml } from './renderers/html-index-core.js';
|
|
18
|
+
// The replay viewer's CSS, shared with the demo's replay-host iframe so it
|
|
19
|
+
// no longer keeps its own hand-synced copy (results.js passes it down).
|
|
20
|
+
export { REPLAY_STYLES_CSS } from './renderers/replay-styles.js';
|
|
21
|
+
// The pure @font-face formatter: the demo fetches the report's WOFF2 files
|
|
22
|
+
// and formats them exactly as the CLI's report-fonts.js does.
|
|
23
|
+
export { fontFaceCss } from './renderers/font-face-css.js';
|
|
18
24
|
export { computeSummary } from './analyzers/summary.js';
|
|
19
25
|
export { detectEdgeExits } from './analyzers/edge-exit.js';
|
|
20
26
|
export { rankTriage } from './analyzers/triage.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/cli/renderers/font-face-css.js
|
|
2
|
+
// The one @font-face formatter for the report's embedded typefaces. Pure (no
|
|
3
|
+
// fs), so both callers share it: the CLI (report-fonts.js reads the WOFF2
|
|
4
|
+
// files from disk) and the browser demo (demo/results.js fetches the same
|
|
5
|
+
// files and gets this through the preview-core bundle). Each manifest entry
|
|
6
|
+
// ({ family, weight, path }) becomes one rule with a base64 data URI.
|
|
7
|
+
//
|
|
8
|
+
// display: 'block' for the CLI report — everything is inline, so a face is
|
|
9
|
+
// never late and must never swap in after a fallback flash.
|
|
10
|
+
|
|
11
|
+
export function fontFaceCss(files, base64Of, display = 'block') {
|
|
12
|
+
return files.map(f =>
|
|
13
|
+
`@font-face { font-family: "${f.family}"; font-style: normal; font-weight: ${f.weight}; ` +
|
|
14
|
+
`font-display: ${display}; src: url(data:font/woff2;base64,${base64Of(f.path)}) format("woff2"); }`
|
|
15
|
+
).join('\n');
|
|
16
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Fonts embedded in the CLI HTML report (report-fonts.js). Latin-subset WOFF2 files redistributed exactly as served by fonts.googleapis.com, unmodified by us; each family is licensed under the SIL Open Font License 1.1 (see <family>/OFL.txt).",
|
|
3
|
+
"fetched": "2026-09-27",
|
|
4
|
+
"license": "OFL-1.1",
|
|
5
|
+
"reservedFontNames": "none declared in any of the six OFL.txt copyright headers (checked 2026-10-01)",
|
|
6
|
+
"licenseSource": "https://raw.githubusercontent.com/google/fonts/main/ofl/<slug>/OFL.txt",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"family": "Space Grotesk",
|
|
10
|
+
"weight": "300 700",
|
|
11
|
+
"variable": true,
|
|
12
|
+
"path": "spacegrotesk/spacegrotesk-300-700.woff2",
|
|
13
|
+
"bytes": 22320,
|
|
14
|
+
"sha256": "a0d054c4af557de20afd6ca59f47ab353bcaec49c63ff04b6c9d39d0f8910557",
|
|
15
|
+
"subset": "latin",
|
|
16
|
+
"source": "https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"family": "Tomorrow",
|
|
20
|
+
"weight": "400",
|
|
21
|
+
"variable": false,
|
|
22
|
+
"path": "tomorrow/tomorrow-400.woff2",
|
|
23
|
+
"bytes": 7736,
|
|
24
|
+
"sha256": "688c7174a13b321d5a1c57547d3775d0732967ec3f87f7647e3dfaefef7ed8a6",
|
|
25
|
+
"subset": "latin",
|
|
26
|
+
"source": "https://fonts.googleapis.com/css2?family=Tomorrow:wght@400;500;600;700&display=swap"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"family": "Sofia Sans",
|
|
30
|
+
"weight": "1 1000",
|
|
31
|
+
"variable": true,
|
|
32
|
+
"path": "sofiasans/sofiasans-1-1000.woff2",
|
|
33
|
+
"bytes": 40520,
|
|
34
|
+
"sha256": "e0ea7bf0ba351883777665cb6d3a1f825387ec7a834e4fcbb8137f03a9bcff26",
|
|
35
|
+
"subset": "latin",
|
|
36
|
+
"source": "https://fonts.googleapis.com/css2?family=Sofia+Sans:wght@1..1000&display=swap"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"family": "Sora",
|
|
40
|
+
"weight": "100 800",
|
|
41
|
+
"variable": true,
|
|
42
|
+
"path": "sora/sora-100-800.woff2",
|
|
43
|
+
"bytes": 33672,
|
|
44
|
+
"sha256": "d2909123a6a8ed2f928055f002c32f63ee93496b470c1a344873f955111fca53",
|
|
45
|
+
"subset": "latin",
|
|
46
|
+
"source": "https://fonts.googleapis.com/css2?family=Sora:wght@100..800&display=swap"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"family": "Recursive",
|
|
50
|
+
"weight": "300 1000",
|
|
51
|
+
"variable": true,
|
|
52
|
+
"path": "recursive/recursive-300-1000.woff2",
|
|
53
|
+
"bytes": 55848,
|
|
54
|
+
"sha256": "b79700b06c097ecdb36ef71d0296ac2825ad7461d6761d3accc12a87c961c07e",
|
|
55
|
+
"subset": "latin",
|
|
56
|
+
"source": "https://fonts.googleapis.com/css2?family=Recursive:wght@300..1000&display=swap"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"family": "Major Mono Display",
|
|
60
|
+
"weight": "400",
|
|
61
|
+
"variable": false,
|
|
62
|
+
"path": "majormonodisplay/majormonodisplay-400.woff2",
|
|
63
|
+
"bytes": 10168,
|
|
64
|
+
"sha256": "97f659d2a626c4b6ad6b79d2840c6626eafd5badc40f995c21843008ed5cb80d",
|
|
65
|
+
"subset": "latin",
|
|
66
|
+
"source": "https://fonts.googleapis.com/css2?family=Major+Mono+Display:wght@400&display=swap"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2018 The Major Mono Project Authors (https://github.com/googlefonts/majormono)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
http://scripts.sil.org/OFL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|