From b847d1740a85b588e7fb1db33775f326af5ab3c5 Mon Sep 17 00:00:00 2001 From: Pierre Le Fevre Date: Sat, 18 Jul 2026 16:11:22 +0800 Subject: [PATCH] Track Opera traffic bundle blocker Fix synthetic bold overstrike for resolved bold font faces and snapshot Opera's missing traffic bundle for offline parity work. The cached bundle now exposes a runtime blocker tracked as isu issue 404 while the parent Opera parity tracker remains open.\n\nRefs isu issue 281\nRefs isu issue 404 --- .isu/issues.json | 15 +++- .../staticfiles/traffic.0f43603a9af9.js | 1 + crates/e2e/scenarios/real-web/opera.com.we | 1 + crates/render/src/atlas.rs | 87 +++++++++++++++++-- 4 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 crates/e2e/real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js diff --git a/.isu/issues.json b/.isu/issues.json index 0eb1567..a7a7988 100644 --- a/.isu/issues.json +++ b/.isu/issues.json @@ -1,5 +1,5 @@ { - "next_id": 404, + "next_id": 405, "issues": [ { "id": 1, @@ -4936,6 +4936,19 @@ "author": "piefev", "state": "open", "created_at": "2026-07-18T07:37:25Z" + }, + { + "id": 404, + "repo": "we", + "title": "Opera traffic bundle throws during offline hydration", + "body": "Parent: isu issue 281. Related: isu issue 335.\\n\\nAfter adding the missing same-origin Opera traffic bundle to the offline snapshot and seeding it in crates/e2e/scenarios/real-web/opera.com.we, the scenario no longer reports a missing fetch for:\\n\\n https://cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js\\n\\nThe bundle now executes, but it throws during both desktop and mobile loads:\\n\\n [script] runtime error in https://cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js: TypeError: Cannot read properties of undefined (reading 'isGX') (line 1:69071)\\n\\nRepro:\\n cargo run -p we-e2e -- --scenario crates/e2e/scenarios/real-web/opera.com.we --out-dir crates/e2e/artifacts\\n\\nCurrent result with the cached traffic bundle:\\n- desktop L101: 64.68% match (433898/1228500 px differ)\\n- mobile L113: 67.81% match (105970/329160 px differ)\\n- DOM and interaction assertions still pass, including the SurveyMonkey container.\\n\\nArtifacts:\\n- crates/e2e/artifacts/real-web/opera.com/desktop.png\\n- crates/e2e/artifacts/real-web/opera.com/desktop.png.diff.png\\n- crates/e2e/artifacts/real-web/opera.com/desktop_dom.txt\\n- crates/e2e/artifacts/real-web/opera.com/desktop_interaction_dom.txt\\n- crates/e2e/artifacts/real-web/opera.com/mobile.png\\n- crates/e2e/artifacts/real-web/opera.com/mobile.png.diff.png\\n- crates/e2e/artifacts/real-web/opera.com/mobile_dom.txt\\n- crates/e2e/artifacts/real-web/opera.com/mobile_interaction_dom.txt\\n\\nInvestigation notes:\\n- A reduced VM test for function/class default parameters with an explicit undefined argument passes, including an arrow factory calling new C(arg).\\n- The failing bundle shape starts around class vt { constructor(r = {}) { ... this.config = { isGX: r.isGX ?? false, ... } } } and is invoked once with an undefined factory argument before a second configured construction.\\n\\nAcceptance criteria:\\n- Minimize the traffic bundle failure to a deterministic JS or DOM-bridge fixture.\\n- Fix the root cause so the cached traffic bundle executes without this TypeError in opera.com.we.\\n- Keep the traffic bundle cache seed in the Opera scenario and continue tracking the remaining Chromium screenshot parity gap under isu issue 281.", + "labels": [ + "real-web" + ], + "assigned": [], + "author": "piefev", + "state": "open", + "created_at": "2026-07-18T08:05:58Z" } ] } diff --git a/crates/e2e/real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js b/crates/e2e/real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js new file mode 100644 index 0000000..c5bc749 --- /dev/null +++ b/crates/e2e/real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js @@ -0,0 +1 @@ +(()=>{var t={1416(t,r,e){var n=e(9138)(e(1433),"DataView");t.exports=n},9073(t,r,e){var n=e(2316),o=e(6458),a=e(2149),i=e(4297),s=e(3121);function c(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1}},21(t){t.exports=function(t,r,e){for(var n=-1,o=null==t?0:t.length;++n=200&&(p=c,f=!1,r=new n(r));t:for(;++l0&&a(l)?e>1?t(l,e-1,a,i,s):n(s,l):i||(s[s.length]=l)}return s}},1469(t,r,e){var n=e(5409)();t.exports=n},1701(t,r,e){var n=e(1469),o=e(1178);t.exports=function(t,r){return t&&n(t,r,o)}},7722(t,r,e){var n=e(7181),o=e(6729);t.exports=function(t,r){for(var e=0,a=(r=n(r,t)).length;null!=t&&eo?0:o+r),(e=e>o?o:e)<0&&(e+=o),o=r>e?0:e-r>>>0,r>>>=0;for(var a=Array(o);++n=o?t:n(t,r,e)}},5936(t,r,e){var n=e(4575);t.exports=function(t,r){for(var e=-1,o=t.length;++e-1;);return e}},7177(t,r,e){var n=e(8944);t.exports=function(t){var r=new t.constructor(t.byteLength);return new n(r).set(new n(t)),r}},7030(t,r,e){t=e.nmd(t);var n=e(1433),o=r&&!r.nodeType&&r,a=o&&t&&!t.nodeType&&t,i=a&&a.exports===o?n.Buffer:void 0,s=i?i.allocUnsafe:void 0;t.exports=function(t,r){if(r)return t.slice();var e=t.length,n=s?s(e):new t.constructor(e);return t.copy(n),n}},4893(t,r,e){var n=e(7177);t.exports=function(t,r){var e=r?n(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.byteLength)}},4021(t){var r=/\w*$/;t.exports=function(t){var e=new t.constructor(t.source,r.exec(t));return e.lastIndex=t.lastIndex,e}},1548(t,r,e){var n=e(2781),o=n?n.prototype:void 0,a=o?o.valueOf:void 0;t.exports=function(t){return a?Object(a.call(t)):{}}},6733(t,r,e){var n=e(7177);t.exports=function(t,r){var e=r?n(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.length)}},9376(t){var r=Math.max;t.exports=function(t,e,n,o){for(var a=-1,i=t.length,s=n.length,c=-1,u=e.length,l=r(i-s,0),p=Array(u+l),f=!o;++c1&&k.reverse(),x&&yl))return!1;var f=c.get(t),h=c.get(r);if(f&&h)return f==r&&h==t;var d=-1,v=!0,g=2&e?new n:void 0;for(c.set(t,r),c.set(r,t);++d1?"& ":"")+e[o],e=e.join(n>2?", ":" "),t.replace(r,"{\n/* [wrapped with "+e+"] */\n")}},8031(t,r,e){var n=e(2781),o=e(1256),a=e(6397),i=n?n.isConcatSpreadable:void 0;t.exports=function(t){return a(t)||o(t)||!!(i&&t&&t[i])}},2845(t){var r=/^(?:0|[1-9]\d*)$/;t.exports=function(t,e){var n=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==n||"symbol"!=n&&r.test(t))&&t>-1&&t%1==0&&t-1}},8291(t,r,e){var n=e(8301);t.exports=function(t,r){var e=this.__data__,o=n(e,t);return o<0?(++this.size,e.push([t,r])):e[o][1]=r,this}},2092(t,r,e){var n=e(9073),o=e(2707),a=e(1955);t.exports=function(){this.size=0,this.__data__={hash:new n,map:new(a||o),string:new n}}},9626(t,r,e){var n=e(5535);t.exports=function(t){var r=n(this,t).delete(t);return this.size-=r?1:0,r}},9925(t,r,e){var n=e(5535);t.exports=function(t){return n(this,t).get(t)}},6809(t,r,e){var n=e(5535);t.exports=function(t){return n(this,t).has(t)}},4385(t,r,e){var n=e(5535);t.exports=function(t,r){var e=n(this,t),o=e.size;return e.set(t,r),this.size+=e.size==o?0:1,this}},953(t){t.exports=function(t){var r=-1,e=Array(t.size);return t.forEach(function(t,n){e[++r]=[n,t]}),e}},3729(t){t.exports=function(t,r){return function(e){return null!=e&&e[t]===r&&(void 0!==r||t in Object(e))}}},9268(t,r,e){var n=e(4556);t.exports=function(t){var r=n(t,function(t){return 500===e.size&&e.clear(),t}),e=r.cache;return r}},2133(t,r,e){var n=e(9376),o=e(7716),a=e(4894),i="__lodash_placeholder__",s=Math.min;t.exports=function(t,r){var e=t[1],c=r[1],u=e|c,l=u<131,p=128==c&&8==e||128==c&&256==e&&t[7].length<=r[8]||384==c&&r[7].length<=r[8]&&8==e;if(!l&&!p)return t;1&c&&(t[2]=r[2],u|=1&e?0:4);var f=r[3];if(f){var h=t[3];t[3]=h?n(h,f,r[4]):f,t[4]=h?a(t[3],i):r[4]}return(f=r[5])&&(h=t[5],t[5]=h?o(h,f,r[6]):f,t[6]=h?a(t[5],i):r[6]),(f=r[7])&&(t[7]=f),128&c&&(t[8]=null==t[8]?r[8]:s(t[8],r[8])),null==t[9]&&(t[9]=r[9]),t[0]=r[0],t[1]=u,t}},3044(t,r,e){var n=e(8499),o=n&&new n;t.exports=o},4558(t,r,e){var n=e(9138)(Object,"create");t.exports=n},9566(t,r,e){var n=e(1019)(Object.keys,Object);t.exports=n},8201(t){t.exports=function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}},3685(t,r,e){t=e.nmd(t);var n=e(5380),o=r&&!r.nodeType&&r,a=o&&t&&!t.nodeType&&t,i=a&&a.exports===o&&n.process,s=function(){try{return a&&a.require&&a.require("util").types||i&&i.binding&&i.binding("util")}catch(t){}}();t.exports=s},1738(t){var r=Object.prototype.toString;t.exports=function(t){return r.call(t)}},1019(t){t.exports=function(t,r){return function(e){return t(r(e))}}},5265(t,r,e){var n=e(6701),o=Math.max;t.exports=function(t,r,e){return r=o(void 0===r?t.length-1:r,0),function(){for(var a=arguments,i=-1,s=o(a.length-r,0),c=Array(s);++i0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}},1848(t,r,e){var n=e(2707);t.exports=function(){this.__data__=new n,this.size=0}},7406(t){t.exports=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e}},8569(t){t.exports=function(t){return this.__data__.get(t)}},3109(t){t.exports=function(t){return this.__data__.has(t)}},3389(t,r,e){var n=e(2707),o=e(1955),a=e(369);t.exports=function(t,r){var e=this.__data__;if(e instanceof n){var i=e.__data__;if(!o||i.length<199)return i.push([t,r]),this.size=++e.size,this;e=this.__data__=new a(i)}return e.set(t,r),this.size=e.size,this}},6547(t){t.exports=function(t,r,e){for(var n=e-1,o=t.length;++n2?r-2:1,n&&n<=r?e:i(e,r)):e}},mixin:function(t){return function(r){var e=this;if(!C(e))return t(e,Object(r));var n=[];return k(P(r),function(t){C(r[t])&&n.push([t,e.prototype[t]])}),t(e,Object(r)),k(n,function(t){var r=t[1];C(r)?e.prototype[t[0]]=r:delete e.prototype[t[0]]}),e}},nthArg:function(t){return function(r){var e=r<0?1:M(r)+1;return T(t(r),e)}},rearg:function(t){return function(r,e){var n=e?e.length:0;return T(t(r,e),n)}},runInContext:function(e){return function(n){return t(r,e(n),l)}}};function U(t,r,e){if(v&&(x||!n.skipFixed[t])){var o=n.methodSpread[t],i=o&&o.start;return void 0===i?E(r,e):function(t,r){return function(){for(var e=arguments.length,n=e-1,o=Array(e);e--;)o[e]=arguments[e];var i=o[r],s=o.slice(0,r);return i&&a.apply(s,i),r!=n&&a.apply(s,o.slice(r+1)),t.apply(this,s)}}(r,i)}return r}function F(t,r,e){return m&&e>1&&(b||!n.skipRearg[t])?S(r,n.methodRearg[t]||n.aryRearg[e]):r}function B(t,r){for(var e=-1,n=(r=D(r)).length,o=n-1,a=j(Object(t)),i=a;null!=i&&++e1?T(r,e):r}(0,o=function(t,r){if(h){var e=n.iterateeRearg[t];if(e)return function(t,r){return q(t,function(t){var e=r.length;return function(t,r){return 2==r?function(r,e){return t.apply(void 0,arguments)}:function(r){return t.apply(void 0,arguments)}}(S(i(t,e),r),e)})}(r,e);var o=!p&&n.iterateeAry[t];if(o)return function(t,r){return q(t,function(t){return"function"==typeof t?i(t,r):t})}(r,o)}return r}(a,o),t),!1}}),!o}),o||(o=u),o==r&&(o=_?T(o,1):function(){return r.apply(this,arguments)}),o.convert=G(a,r),o.placeholder=r.placeholder=e,o}if(!f)return $(e,u,y);var z=u,K=[];return k(N,function(t){k(n.aryMethod[t],function(t){var r=z[n.remap[t]||t];r&&K.push([t,$(t,r,z)])})}),k(P(z),function(t){var r=z[t];if("function"==typeof r){for(var e=K.length;e--;)if(K[e][0]==t)return;r.convert=G(t,r),K.push([t,r])}}),k(K,function(t){z[t[0]]=t[1]}),z.convert=function(t){return z.runInContext.convert(t)(void 0)},z.placeholder=z,k(P(z),function(t){k(n.realToAlias[t]||[],function(r){z[r]=z[t]})}),z}},6929(t){t.exports={cap:!1,curry:!1,fixed:!1,immutable:!1,rearg:!1}},3166(t,r){r.aliasToReal={each:"forEach",eachRight:"forEachRight",entries:"toPairs",entriesIn:"toPairsIn",extend:"assignIn",extendAll:"assignInAll",extendAllWith:"assignInAllWith",extendWith:"assignInWith",first:"head",conforms:"conformsTo",matches:"isMatch",property:"get",__:"placeholder",F:"stubFalse",T:"stubTrue",all:"every",allPass:"overEvery",always:"constant",any:"some",anyPass:"overSome",apply:"spread",assoc:"set",assocPath:"set",complement:"negate",compose:"flowRight",contains:"includes",dissoc:"unset",dissocPath:"unset",dropLast:"dropRight",dropLastWhile:"dropRightWhile",equals:"isEqual",identical:"eq",indexBy:"keyBy",init:"initial",invertObj:"invert",juxt:"over",omitAll:"omit",nAry:"ary",path:"get",pathEq:"matchesProperty",pathOr:"getOr",paths:"at",pickAll:"pick",pipe:"flow",pluck:"map",prop:"get",propEq:"matchesProperty",propOr:"getOr",props:"at",symmetricDifference:"xor",symmetricDifferenceBy:"xorBy",symmetricDifferenceWith:"xorWith",takeLast:"takeRight",takeLastWhile:"takeRightWhile",unapply:"rest",unnest:"flatten",useWith:"overArgs",where:"conformsTo",whereEq:"isMatch",zipObj:"zipObject"},r.aryMethod={1:["assignAll","assignInAll","attempt","castArray","ceil","create","curry","curryRight","defaultsAll","defaultsDeepAll","floor","flow","flowRight","fromPairs","invert","iteratee","memoize","method","mergeAll","methodOf","mixin","nthArg","over","overEvery","overSome","rest","reverse","round","runInContext","spread","template","trim","trimEnd","trimStart","uniqueId","words","zipAll"],2:["add","after","ary","assign","assignAllWith","assignIn","assignInAllWith","at","before","bind","bindAll","bindKey","chunk","cloneDeepWith","cloneWith","concat","conformsTo","countBy","curryN","curryRightN","debounce","defaults","defaultsDeep","defaultTo","delay","difference","divide","drop","dropRight","dropRightWhile","dropWhile","endsWith","eq","every","filter","find","findIndex","findKey","findLast","findLastIndex","findLastKey","flatMap","flatMapDeep","flattenDepth","forEach","forEachRight","forIn","forInRight","forOwn","forOwnRight","get","groupBy","gt","gte","has","hasIn","includes","indexOf","intersection","invertBy","invoke","invokeMap","isEqual","isMatch","join","keyBy","lastIndexOf","lt","lte","map","mapKeys","mapValues","matchesProperty","maxBy","meanBy","merge","mergeAllWith","minBy","multiply","nth","omit","omitBy","overArgs","pad","padEnd","padStart","parseInt","partial","partialRight","partition","pick","pickBy","propertyOf","pull","pullAll","pullAt","random","range","rangeRight","rearg","reject","remove","repeat","restFrom","result","sampleSize","some","sortBy","sortedIndex","sortedIndexOf","sortedLastIndex","sortedLastIndexOf","sortedUniqBy","split","spreadFrom","startsWith","subtract","sumBy","take","takeRight","takeRightWhile","takeWhile","tap","throttle","thru","times","trimChars","trimCharsEnd","trimCharsStart","truncate","union","uniqBy","uniqWith","unset","unzipWith","without","wrap","xor","zip","zipObject","zipObjectDeep"],3:["assignInWith","assignWith","clamp","differenceBy","differenceWith","findFrom","findIndexFrom","findLastFrom","findLastIndexFrom","getOr","includesFrom","indexOfFrom","inRange","intersectionBy","intersectionWith","invokeArgs","invokeArgsMap","isEqualWith","isMatchWith","flatMapDepth","lastIndexOfFrom","mergeWith","orderBy","padChars","padCharsEnd","padCharsStart","pullAllBy","pullAllWith","rangeStep","rangeStepRight","reduce","reduceRight","replace","set","slice","sortedIndexBy","sortedLastIndexBy","transform","unionBy","unionWith","update","xorBy","xorWith","zipWith"],4:["fill","setWith","updateWith"]},r.aryRearg={2:[1,0],3:[2,0,1],4:[3,2,0,1]},r.iterateeAry={dropRightWhile:1,dropWhile:1,every:1,filter:1,find:1,findFrom:1,findIndex:1,findIndexFrom:1,findKey:1,findLast:1,findLastFrom:1,findLastIndex:1,findLastIndexFrom:1,findLastKey:1,flatMap:1,flatMapDeep:1,flatMapDepth:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1,transform:2},r.iterateeRearg={mapKeys:[1],reduceRight:[1,0]},r.methodRearg={assignInAllWith:[1,0],assignInWith:[1,2,0],assignAllWith:[1,0],assignWith:[1,2,0],differenceBy:[1,2,0],differenceWith:[1,2,0],getOr:[2,1,0],intersectionBy:[1,2,0],intersectionWith:[1,2,0],isEqualWith:[1,2,0],isMatchWith:[2,1,0],mergeAllWith:[1,0],mergeWith:[1,2,0],padChars:[2,1,0],padCharsEnd:[2,1,0],padCharsStart:[2,1,0],pullAllBy:[2,1,0],pullAllWith:[2,1,0],rangeStep:[1,2,0],rangeStepRight:[1,2,0],setWith:[3,1,2,0],sortedIndexBy:[2,1,0],sortedLastIndexBy:[2,1,0],unionBy:[1,2,0],unionWith:[1,2,0],updateWith:[3,1,2,0],xorBy:[1,2,0],xorWith:[1,2,0],zipWith:[1,2,0]},r.methodSpread={assignAll:{start:0},assignAllWith:{start:0},assignInAll:{start:0},assignInAllWith:{start:0},defaultsAll:{start:0},defaultsDeepAll:{start:0},invokeArgs:{start:2},invokeArgsMap:{start:2},mergeAll:{start:0},mergeAllWith:{start:0},partial:{start:1},partialRight:{start:1},without:{start:1},zipAll:{start:0}},r.mutate={array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0,pullAllWith:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignAll:!0,assignAllWith:!0,assignIn:!0,assignInAll:!0,assignInAllWith:!0,assignInWith:!0,assignWith:!0,defaults:!0,defaultsAll:!0,defaultsDeep:!0,defaultsDeepAll:!0,merge:!0,mergeAll:!0,mergeAllWith:!0,mergeWith:!0},set:{set:!0,setWith:!0,unset:!0,update:!0,updateWith:!0}},r.realToAlias=function(){var t=Object.prototype.hasOwnProperty,e=r.aliasToReal,n={};for(var o in e){var a=e[o];t.call(n,a)?n[a].push(o):n[a]=[o]}return n}(),r.remap={assignAll:"assign",assignAllWith:"assignWith",assignInAll:"assignIn",assignInAllWith:"assignInWith",curryN:"curry",curryRightN:"curryRight",defaultsAll:"defaults",defaultsDeepAll:"defaultsDeep",findFrom:"find",findIndexFrom:"findIndex",findLastFrom:"findLast",findLastIndexFrom:"findLastIndex",getOr:"get",includesFrom:"includes",indexOfFrom:"indexOf",invokeArgs:"invoke",invokeArgsMap:"invokeMap",lastIndexOfFrom:"lastIndexOf",mergeAll:"merge",mergeAllWith:"mergeWith",padChars:"pad",padCharsEnd:"padEnd",padCharsStart:"padStart",propertyOf:"get",rangeStep:"range",rangeStepRight:"rangeRight",restFrom:"rest",spreadFrom:"spread",trimChars:"trim",trimCharsEnd:"trimEnd",trimCharsStart:"trimStart",zipAll:"zip"},r.skipFixed={castArray:!0,flow:!0,flowRight:!0,iteratee:!0,mixin:!0,rearg:!0,runInContext:!0},r.skipRearg={add:!0,assign:!0,assignIn:!0,bind:!0,bindKey:!0,concat:!0,difference:!0,divide:!0,eq:!0,gt:!0,gte:!0,isEqual:!0,lt:!0,lte:!0,matchesProperty:!0,merge:!0,multiply:!0,overArgs:!0,partial:!0,partialRight:!0,propertyOf:!0,random:!0,range:!0,rangeRight:!0,subtract:!0,zip:!0,zipObject:!0,zipObjectDeep:!0}},6866(t,r,e){t.exports={ary:e(4190),assign:e(1145),clone:e(5841),curry:e(6231),forEach:e(149),isArray:e(6397),isError:e(2246),isFunction:e(8446),isWeakMap:e(978),iteratee:e(4667),keys:e(1452),rearg:e(767),toInteger:e(9445),toPath:e(8916)}},9132(t,r,e){var n=e(1972),o=e(6866);t.exports=function(t,r,e){return n(o,t,r,e)}},640(t,r,e){var n=e(9132)("difference",e(8222));n.placeholder=e(8286),t.exports=n},1335(t,r,e){var n=e(9132)("flow",e(6898));n.placeholder=e(8286),t.exports=n},3350(t,r,e){var n=e(9132)("fromPairs",e(2605));n.placeholder=e(8286),t.exports=n},9731(t,r,e){var n=e(9132)("get",e(2832));n.placeholder=e(8286),t.exports=n},5038(t,r,e){var n=e(9132)("includes",e(9007));n.placeholder=e(8286),t.exports=n},4955(t,r,e){var n=e(9132)("isUndefined",e(788),e(6929));n.placeholder=e(8286),t.exports=n},1295(t,r,e){var n=e(9132)("join",e(9230));n.placeholder=e(8286),t.exports=n},2595(t,r,e){var n=e(9132)("keys",e(1178),e(6929));n.placeholder=e(8286),t.exports=n},3201(t,r,e){var n=e(9132)("map",e(4214));n.placeholder=e(8286),t.exports=n},8286(t){t.exports={}},343(t,r,e){var n=e(9132)("split",e(8804));n.placeholder=e(8286),t.exports=n},413(t,r,e){var n=e(9132)("toPairs",e(4502),e(6929));n.placeholder=e(8286),t.exports=n},9240(t,r,e){var n=e(9132)("trimCharsStart",e(2284));n.placeholder=e(8286),t.exports=n},2605(t){t.exports=function(t){for(var r=-1,e=null==t?0:t.length,n={};++r-1:!!l&&n(t,r,e)>-1}},1256(t,r,e){var n=e(9250),o=e(2934),a=Object.prototype,i=a.hasOwnProperty,s=a.propertyIsEnumerable,c=n(function(){return arguments}())?n:function(t){return o(t)&&i.call(t,"callee")&&!s.call(t,"callee")};t.exports=c},6397(t){var r=Array.isArray;t.exports=r},8330(t,r,e){var n=e(8446),o=e(3330);t.exports=function(t){return null!=t&&o(t.length)&&!n(t)}},5569(t,r,e){var n=e(8330),o=e(2934);t.exports=function(t){return o(t)&&n(t)}},492(t,r,e){t=e.nmd(t);var n=e(1433),o=e(659),a=r&&!r.nodeType&&r,i=a&&t&&!t.nodeType&&t,s=i&&i.exports===a?n.Buffer:void 0,c=(s?s.isBuffer:void 0)||o;t.exports=c},2246(t,r,e){var n=e(7148),o=e(2934),a=e(4679);t.exports=function(t){if(!o(t))return!1;var r=n(t);return"[object Error]"==r||"[object DOMException]"==r||"string"==typeof t.message&&"string"==typeof t.name&&!a(t)}},8446(t,r,e){var n=e(7148),o=e(8953);t.exports=function(t){if(!o(t))return!1;var r=n(t);return"[object Function]"==r||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}},3330(t){t.exports=function(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991}},422(t,r,e){var n=e(4800),o=e(41),a=e(3685),i=a&&a.isMap,s=i?o(i):n;t.exports=s},8953(t){t.exports=function(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}},2934(t){t.exports=function(t){return null!=t&&"object"==typeof t}},4679(t,r,e){var n=e(7148),o=e(3347),a=e(2934),i=Function.prototype,s=Object.prototype,c=i.toString,u=s.hasOwnProperty,l=c.call(Object);t.exports=function(t){if(!a(t)||"[object Object]"!=n(t))return!1;var r=o(t);if(null===r)return!0;var e=u.call(r,"constructor")&&r.constructor;return"function"==typeof e&&e instanceof e&&c.call(e)==l}},2739(t,r,e){var n=e(4289),o=e(41),a=e(3685),i=a&&a.isRegExp,s=i?o(i):n;t.exports=s},3764(t,r,e){var n=e(7866),o=e(41),a=e(3685),i=a&&a.isSet,s=i?o(i):n;t.exports=s},7571(t,r,e){var n=e(7148),o=e(6397),a=e(2934);t.exports=function(t){return"string"==typeof t||!o(t)&&a(t)&&"[object String]"==n(t)}},5414(t,r,e){var n=e(7148),o=e(2934);t.exports=function(t){return"symbol"==typeof t||o(t)&&"[object Symbol]"==n(t)}},7995(t,r,e){var n=e(7129),o=e(41),a=e(3685),i=a&&a.isTypedArray,s=i?o(i):n;t.exports=s},788(t){t.exports=function(t){return void 0===t}},978(t,r,e){var n=e(1201),o=e(2934);t.exports=function(t){return o(t)&&"[object WeakMap]"==n(t)}},4667(t,r,e){var n=e(2931),o=e(1454);t.exports=function(t){return o("function"==typeof t?t:n(t,1))}},9230(t){var r=Array.prototype.join;t.exports=function(t,e){return null==t?"":r.call(t,e)}},1178(t,r,e){var n=e(1163),o=e(1452),a=e(8330);t.exports=function(t){return a(t)?n(t):o(t)}},5405(t,r,e){var n=e(1163),o=e(1491),a=e(8330);t.exports=function(t){return a(t)?n(t,!0):o(t)}},4214(t,r,e){var n=e(4272),o=e(1454),a=e(3892),i=e(6397);t.exports=function(t,r){return(i(t)?n:a)(t,o(r,3))}},4556(t,r,e){var n=e(369);function o(t,r){if("function"!=typeof t||null!=r&&"function"!=typeof r)throw new TypeError("Expected a function");var e=function(){var n=arguments,o=r?r.apply(this,n):n[0],a=e.cache;if(a.has(o))return a.get(o);var i=t.apply(this,n);return e.cache=a.set(o,i)||a,i};return e.cache=new(o.Cache||n),e}o.Cache=n,t.exports=o},5114(t){t.exports=function(){}},5795(t,r,e){var n=e(3305),o=e(5267),a=e(3726),i=e(6729);t.exports=function(t){return a(t)?n(i(t)):o(t)}},767(t,r,e){var n=e(7557),o=e(9820)(function(t,r){return n(t,256,void 0,void 0,void 0,r)});t.exports=o},8804(t,r,e){var n=e(6584),o=e(9270),a=e(654),i=e(6220),s=e(2739),c=e(4092),u=e(3506);t.exports=function(t,r,e){return e&&"number"!=typeof e&&i(t,r,e)&&(r=e=void 0),(e=void 0===e?4294967295:e>>>0)?(t=u(t))&&("string"==typeof r||null!=r&&!s(r))&&!(r=n(r))&&a(t)?o(c(t),0,e):t.split(r,e):[]}},3629(t){t.exports=function(){return[]}},659(t){t.exports=function(){return!1}},4764(t,r,e){var n=e(5378),o=1/0;t.exports=function(t){return t?(t=n(t))===o||t===-1/0?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}},9445(t,r,e){var n=e(4764);t.exports=function(t){var r=n(t),e=r%1;return r==r?e?r-e:r:0}},5378(t,r,e){var n=e(8812),o=e(8953),a=e(5414),i=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,c=/^0o[0-7]+$/i,u=parseInt;t.exports=function(t){if("number"==typeof t)return t;if(a(t))return NaN;if(o(t)){var r="function"==typeof t.valueOf?t.valueOf():t;t=o(r)?r+"":r}if("string"!=typeof t)return 0===t?t:+t;t=n(t);var e=s.test(t);return e||c.test(t)?u(t.slice(2),e?2:8):i.test(t)?NaN:+t}},4502(t,r,e){var n=e(9495)(e(1178));t.exports=n},8916(t,r,e){var n=e(4272),o=e(8835),a=e(6397),i=e(5414),s=e(3614),c=e(6729),u=e(3506);t.exports=function(t){return a(t)?n(t,c):i(t)?[t]:o(s(u(t)))}},3506(t,r,e){var n=e(6584);t.exports=function(t){return null==t?"":n(t)}},2284(t,r,e){var n=e(6584),o=e(9270),a=e(5936),i=e(4092),s=e(3506),c=/^\s+/;t.exports=function(t,r,e){if((t=s(t))&&(e||void 0===r))return t.replace(c,"");if(!t||!(r=n(r)))return t;var u=i(t),l=a(u,i(r));return o(u,l).join("")}},3308(t,r,e){var n=e(7838),o=e(1178);t.exports=function(t){return null==t?[]:n(t,o(t))}},7810(t,r,e){var n=e(5432),o=e(9381),a=e(7701),i=e(6397),s=e(2934),c=e(4517),u=Object.prototype.hasOwnProperty;function l(t){if(s(t)&&!i(t)&&!(t instanceof n)){if(t instanceof o)return t;if(u.call(t,"__wrapped__"))return c(t)}return new o(t)}l.prototype=a.prototype,l.prototype.constructor=l,t.exports=l}},r={};function e(n){var o=r[n];if(void 0!==o)return o.exports;var a=r[n]={id:n,loaded:!1,exports:{}};return t[n](a,a.exports,e),a.loaded=!0,a.exports}e.n=t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},e.d=(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},e.o=(t,r)=>Object.prototype.hasOwnProperty.call(t,r),e.nmd=t=>(t.paths=[],t.children||(t.children=[]),t),(()=>{"use strict";var t;!function(t){t.ANCHOR="a",t.BODY="body",t.DIV="div",t.FOOTER="footer",t.IFRAME="iframe",t.IMAGE="img",t.INPUT="input",t.HEADER="header",t.SECTION="section",t.SCRIPT="script",t.OPTION="option",t.SPAN="span",t.LI="li",t.P="p",t.HR="hr",t.H3="h3"}(t||(t={}));const r="",n=(document.getElementsByTagName(t.HEADER)[0],document.getElementsByTagName(t.FOOTER)[0],document.getElementsByTagName(t.BODY)[0],"data-utm-override"),o=window.location.host,a=o.replace(/^www\./,r).replace(/\./g,"_");var i,s;!function(t){t.NONE="none",t.INITIAL="initial",t.INLINE_BLOCK="inline-block",t.BLOCK="block",t.FLEX="flex"}(i||(i={})),function(t){t.BEFOREUNLOAD="beforeunload",t.BLUR="blur",t.FOCUS="focus",t.CLICK="click",t.KEY_UP="keyup",t.KEY_DOWN="keydown",t.INPUT="input",t.SCROLL="scroll",t.RESIZE="resize",t.HASHCHANGE="hashchange",t.ORIENTATION_CHANGE="orientationChange",t.LOAD="load",t.CHANGE="change",t.MESSAGE="message",t.WHEEL="wheel",t.MOUSEMOVE="mousemove",t.MOUSEOVER="mouseover",t.MOUSEENTER="mouseenter",t.MOUSEOUT="mouseout",t.MOUSELEAVE="mouseleave",t.TOUCHSTART="touchstart",t.TOUCHMOVE="touchmove",t.MEDIA_ENDED="ended",t.REFRESH_INIT="refreshInit",t.SUBMIT="submit",t.FORM_SUCCESS="formSuccess"}(s||(s={}));var c=e(1335),u=e.n(c),l=e(9240),p=e.n(l),f=e(343),h=e.n(f),d=e(3201),v=e.n(d),g=e(4955),m=e.n(g),y=e(3350),_=e.n(y);const x=(window.operaLogger||(window.operaLogger=localStorage.verbose&&"true"===localStorage.verbose?Object.assign({},console):Object.assign({},(()=>{const t={};return Object.keys(console).forEach(r=>{t[r]=()=>{}}),t})())),window.operaLogger);class b{getGeoData(){const t=C(b.LOCAL_COUNTRY_KEY),r=C(b.LOCAL_CONTINENT_KEY);return new Promise((e,n)=>{if(t)x.log("Geo: using Local storage",t,r),e(JSON.parse(`{"country":"${t}", "continent":"${r}"}`));else{x.log("Geo: getting data from api");const t=location.protocol+"//"+o+"/api/geolocation/",r=new XMLHttpRequest;r.onreadystatechange=function(t){if(4===r.readyState)if(r.status>=200&&r.status<300){const t=JSON.parse(r.responseText);R(b.LOCAL_COUNTRY_KEY,t.country,b.LOCAL_STORAGE_EXPIRATION),R(b.LOCAL_CONTINENT_KEY,t.continent,b.LOCAL_STORAGE_EXPIRATION),e(t)}else n(r.statusText)},r.open("GET",t,!0),r.send()}})}}b.LOCAL_COUNTRY_KEY="geo_country",b.LOCAL_CONTINENT_KEY="geo_continent",b.LOCAL_STORAGE_EXPIRATION=864e5;const w=t=>{const e=document.cookie.match(`(^|[^;]+)\\s*${t}\\s*=\\s*([^;]+)`);return(e?e.pop():r)||r},A=t=>t.replace(/^(.*):\d+$/,"$1").replace(/(?:.*\.)?([^\.]+\.[^\.]+)$/,"$1"),E=t=>m()(t)?r:t,O=(t,r)=>{const e=p()("?",r);if(!e)return t;const n=t.replace(/[&?]+$/,"");return n.indexOf("?")>0?`${n}&${e}`:`${n}?${e}`},j=t=>t?u()(p()("?"),h()("&"),v()(t=>h()("=",t)),_())(t):{},T=t=>{const r=t.match(/^(https?\:)\/\/([^\/?#]*)([\/]{0,1}[^?#]*)/);return{href:t,protocol:r[1],host:r[2],pathname:r[3]||"/"}},k=t=>t?t.replace(/[^\w \(\)\[\]\-\.\+@\/:%]/g,"_"):r,I=t=>{if("opera_com"===t){const t=window.location.pathname;if(/\/campaign\//.test(t)){const r=t.match(/^(?:\/\w{2}(?:-\w{2,3})?)?\/campaign\/([^\/]+)/);if(r)return r[1]}}return r},R=(t,r,e)=>{const n={value:r,expire:(new Date).getTime()+e};localStorage.setItem(t,JSON.stringify(n))},C=t=>{const r=localStorage.getItem(t);if(!r)return null;const e=JSON.parse(r);return(new Date).getTime()>e.expire?(localStorage.removeItem(t),null):e.value},L=t=>t.replace(/-/g,"_");var P=e(1295),S=e.n(P),M=e(413),D=e.n(M);class N{constructor(){this.applyParamsToLink=(t,r)=>N.APP_STORE_LINK_REGEX.test(t.href)?this.applyParamsToAppStoreLink(t,r):N.GOOGLE_PLAY_LINK_REGEX.test(t.href)&&!t.hasAttribute(n)?this.applyParamsToGooglePlayLink(t,r):N.GX_LP_REGEX_GOOGLE.test(t.href)&&!t.hasAttribute(n)?this.applyParamsToGoogleGXRebrandlyLink(t):N.GX_LP_REGEX_APPLE.test(t.href)&&!t.hasAttribute(n)?this.applyParamsToGXAppleRebrandlyLink(t):t.href,this.mapValue=(t,r)=>k(t)+r}generateParams(t){if(t){const r="";return this.convertClassificationToStringParams(t,r)}return this.generateNoCookieParams(r)}applyParamsToGoogleGXRebrandlyLink(t){const r=window.location.search,e=r?`?referrer=${encodeURIComponent(p()("?",r))}`:"";return O(t.href,e)}applyParamsToGXAppleRebrandlyLink(t){const r=j(window.location.search).utm_campaign,e=r?`?pt=118728196&ct=${r}&mt=8`:"";return O(t.href,e)}applyParamsToGooglePlayLink(t,r){return t.href}applyParamsToAppStoreLink(t,r){return t.href}fullName(t){if(t&&t.site)return k(t.site)+(t.sub?`_${k(t.sub)}`:r);const e=I(a);return a+(e?`_${e}`:r)}generateNoCookieParams(t){return`http_referrer=missing${t}&utm_source=(nocookie)${t}&utm_medium=doc&utm_campaign=(nocookie)${t}`}convertClassificationToStringParams(t,e){return u()(D(),v()(([t,n])=>"referrer"===t?`http_${t}=${n?this.mapValue(n,r):this.mapValue("missing",e)}`:"campaign"===t||"source"===t?n?`utm_${t}=${this.mapValue(n,e)}`:r:"gclsrc"===t||"gclid"===t||"dclid"===t||"edition"===t||"utm_reclassified"===t?n?`${t}=${this.mapValue(n,r)}`:r:n?`utm_${t}=${this.mapValue(n,r)}`:r),t=>t.filter(t=>t!==r),S()("&"))(t)}}N.GOOGLE_PLAY_LINK_REGEX=/(play\.google\.com|^market:\/\/)/,N.APP_STORE_LINK_REGEX=/itunes\.apple\.com/,N.GX_LP_REGEX_GOOGLE=/operagx\.gg\/mobile-lp-android/,N.GX_LP_REGEX_APPLE=/operagx\.gg\/mobile-lp-ios/;const W=(window.operaTrackingParamsService||(window.operaTrackingParamsService=new N),window.operaTrackingParamsService);class U{constructor(t){this.domainFamily=t}get(t=U.COOKIE_NAME){return w(t)}getClassification(t){return t?u()(h()("&"),v()(t=>h()("=",t)),_())(decodeURIComponent(t)):void 0}setClassification(t,r,e){const n=u()(D(),v()(t=>`${encodeURIComponent(t[0])}=${encodeURIComponent(t[1])}`),S()("&"))(r),o=e||`.${this.domainFamily}`;((t,r,e)=>{const n=new Date;n.setMonth(n.getMonth()+6);const o=n;document.cookie=`${t}=${encodeURIComponent(r)};expires=${o.toUTCString()};path=/;domain=${e}`})(t,n,o),x.log("[CookieManager] Classification cookie set",{cookieName:t,domain:o,source:r.source,medium:r.medium})}}U.COOKIE_NAME="opref";var F,B,G,q=e(9731),$=e.n(q),z=e(640),K=e.n(z),X=e(2595),V=e.n(X);!function(t){t.SOCIAL="sm",t.REFERRAL="roc",t.ORGANIC="ose",t.DIRECT="doc",t.PAID="pa",t.PAID_DISTRIBUTION="pd",t.PAID_BRANDED="ba_ose"}(F||(F={})),function(t){t.SOCIAL="(social)",t.DIRECT="(direct)",t.PAID="adwords",t.NONE="(none)"}(B||(B={})),function(t){t.DIRECT="(direct)",t.PAID="google-ads"}(G||(G={}));class Y{constructor(t,r,e,n){this.source=t,this.medium=r,this.campaign=e,n&&(this.edition=n)}}class H extends Y{constructor(t){super(t.key,F.ORGANIC,B.NONE)}}class J extends Y{constructor(t){super(t.domain.replace(/^www\./,r),F.REFERRAL,B.NONE),this.content=t.path}}class Q extends Y{constructor(t){super(t.key,F.SOCIAL,B.SOCIAL),this.content=t.path}}class Z extends Y{constructor(){super(G.DIRECT,F.DIRECT,B.DIRECT)}}class tt extends Y{constructor(t){const r=!m()($()("utm_campaign",t)),e=!m()($()("utm_content",t)),n=r?$()("utm_campaign",t):B.PAID,o=e?$()("utm_content",t):"google cpc";super(G.PAID,/branded/i.test(n)?F.PAID_BRANDED:F.PAID,n),this.content=o,this.id=`gclid${$()("gclid",t)}`}}class rt extends Y{constructor(t,r,e){super(t.utm_source,r,t.utm_campaign,t.edition),this.content=E(t.utm_content),this.id=e}}class et extends Y{constructor(t){super(t.utm_source||"",t.utm_medium||"",t.utm_campaign||"",t.edition),this.gclsrc=t.gclsrc,this.dclid=t.dclid||"",this.gclid=t.gclid||""}}var nt=e(5038),ot=e.n(nt);class at{constructor(t,e,n){this.domain=t,this.domainFamily=A(t),this.key=r,this.path=e,this.query=n}}const it={"360.cn":"q",aol:["q","query","encquery"],ask:["q","yoursearch"],auone:"q",avg:"q",babylon:"q",baidu:"wd",baisvik:"q",biglobe:"s",bing:"q",comcast:"q",conduit:"q",daum:"q",duckduckgo:null,globo:"q","go.mail.ru":"q","images.google":"q",google:"q",incredimail:"q",kvasir:"q",lycos:"q",mail:"q",myway:"searchfor",naver:"query",onet:"qt",rakuten:null,rambler:"query",safehomepage:"q","search-results":"q","search.smt.docomo":"search_box",seznam:"q",smartshopping:"keywords",snapdo:"q","so.com":"q",sogou:"query",startsiden:"q","tut.by":"query",ukr:"q",uninstallmaster:"q",virgilio:"qs","vi-view.com":"q",yahoo:"p",yandex:"text",yoursearch:"q",webcrawler:"q",webssearches:"q",wow:"o_q",zum:"query",live:"q"},st={"blogspot.com":"blogspot","cloob.com":"cloob","deviantart.com":"deviantart","disqus.com":"disqus","facebook.com":"facebook","my.opera.com":"myopera","odnoklassniki.ru":"odnoklassniki","plus.google.com":"google_plus","plus.url.google.com":"google_plus","twitter.com":"twitter","vk.com":"vk","vkontakte.ru":"vkontakte","youtube.com":"youtube"};class ct{generateReferrerFromUrl(t){const e=t.match(/.*?(?:\:\/\/)([^\/\:]+)(?:[^\/]*)?(\/+[^\?]*)?(\?[^#]*)?.*/),n=e&&e[1].toLowerCase()||r;return new at(n,e&&e[2]||r,e&&e[3]||r)}isFromSocialSite(t){let r=!1;return u()(v()(e=>{if(ot()(e,t.domain))return t.key=st[e],r=!0,!1}))(V()(st)),r}isFromSearchEngine(t){let r=!1;return u()(v()(e=>{if(ot()(e,t.domain))return t.key=e,r=!0,!1}))(V()(it)),r}isValid(t,r,e,n){return t.domain&&t.domain!==r&&t.domainFamily!==e||!n}}class ut{constructor(t,r,e,n,o){this.parameters=t,this.domainFamily=r,this.subName=e,this.domain=n,this.cookieManager=o,this.referrerAnalyzer=new ct}classify(){const t=$()(ut.UTM_REFERRER_KEY,this.parameters),e="about:blank"===document.referrer?r:document.referrer,n=t||e;let o=this.resolveClassification(n);if(x.log("[TrafficClassifier] Initial classification",{type:o.constructor.name,referrerUrl:n}),o instanceof J&&n)try{const t=new URL(n),r=t.hostname.toLowerCase();if(r.includes("opera.com")){const e=j(t.search);if(this.hasUTMTriplet(e)||this.hasGoogleAdsParams(e)||$()("gclid",e)){x.log("[TrafficClassifier] OPCOM-14584 fallback: reclassifying from opera.com referrer",{referrerDomain:r,hasUTMTriplet:this.hasUTMTriplet(e),hasGoogleAds:this.hasGoogleAdsParams(e),hasGclid:!!$()("gclid",e)});const t=this.parameters;this.parameters=e,o=this.resolveClassification(n),o.utm_reclassified="true",this.parameters=t,x.log("[TrafficClassifier] Reclassified to",{type:o.constructor.name,source:o.source,medium:o.medium})}}}catch(t){x.error("[TrafficClassifier] Error parsing referrer URL",{error:t,referrerUrl:n})}return o&&(o.referrer=n,o.site=a,o.sub=this.subName,this.cookieManager.setClassification(U.COOKIE_NAME,o),x.log("[TrafficClassifier] Final classification saved to cookie",{type:o.constructor.name,source:o.source,medium:o.medium,campaign:o.campaign,reclassified:o.utm_reclassified})),o}resolveClassification(t){if(this.hasGoogleAdsParams(this.parameters))return new et(this.parameters);if(this.hasUTMTriplet(this.parameters)){const t=this.cookieManager.get(),r=this.cookieManager.getClassification(t);if(r&&this.isUTMTripletEqual(this.parameters,r)){x.log("[TrafficClassifier] UTM triplet matches cookie, using classification from cookie",{source:r.source,medium:r.medium,campaign:r.campaign});const t=new rt(this.parameters,r.medium,r.id||this.resolveId(this.parameters));return r.utm_reclassified&&(t.utm_reclassified=r.utm_reclassified),t}const e=this.resolveId(this.parameters),n=this.resolveMedium(this.parameters);return new rt(this.parameters,n,e)}if($()("gclid",this.parameters))return new tt(this.parameters);if(t){const r=this.referrerAnalyzer.generateReferrerFromUrl(t),e=!!this.cookieManager.get();if(this.referrerAnalyzer.isValid(r,this.domain,this.domainFamily,e))return this.resolveReferrerClassification(r)}return new Z}hasUTMTriplet(t){return K()(ut.UTM_REQUIRED_KEYS,V()(t)).length<1}hasGoogleAdsParams(t){return V()(t).includes(ut.GOOGLE_KEYS[0])&&(V()(t).includes(ut.GOOGLE_KEYS[1])||V()(t).includes(ut.GOOGLE_KEYS[2]))}isUTMTripletEqual(t,r){return t.utm_source===r.source&&t.utm_medium===r.medium&&t.utm_campaign===r.campaign}resolveReferrerClassification(t){return this.referrerAnalyzer.isFromSocialSite(t)?new Q(t):this.referrerAnalyzer.isFromSearchEngine(t)?new H(t):new J(t)}resolveMedium(t){return t.utm_medium===F.PAID&&("bing"===t.utm_source&&/brand/i.test(t.utm_campaign)||"yandex"===t.utm_source&&/_brand_/i.test(t.utm_campaign))?F.PAID_BRANDED:t.utm_medium}resolveId(t){const r=$()("msclkid",t);return r?`msclkid_${r}`:E(t.utm_id)}}ut.UTM_REFERRER_KEY="utm_referrer",ut.UTM_REQUIRED_KEYS=["utm_source","utm_medium","utm_campaign"],ut.GOOGLE_KEYS=["gclsrc","dclid","gclid"];const lt=[{sourcePattern:/utm_source=avira/,edition:"avira"},{sourcePattern:/utm_source=softonic/,campaignPattern:/utm_campaign=search_ru/,edition:"Yx%2003"}],pt=["cnsnt-grntd","cnsnt-mktg","cnsnt-ga","usr","gxme_referral_code"];class ft{constructor(t,r,e,n={}){this.cookieManager=t,this.trafficClassifier=r,this.abTestManager=e,this.applyTrackingForDownloadLink=t=>{const r=w(U.COOKIE_NAME),e=this.cookieManager.getClassification(r),n=W.generateParams(e);let o=t.href,a=!1;if(/net\.geo\.opera\.com/.test(o)){a=!0;const r=o.indexOf("http_referrer=");r>0&&(o=o.substring(0,r-1)),o=O(o,n),o=this.extendParamsWithEditionParam(o);const e=(t=>Object.entries(t).map(([t,r])=>`${encodeURIComponent(t)}=${encodeURIComponent(r)}`).join("&"))((t=>{if(!t)return{};const r=new URLSearchParams(t),e={};for(const t of pt){const n=r.get(t);null!==n&&""!==n&&(e[`fast_onboarding_${L(t)}`]=n)}return e})(window.location.search));if(e&&(o=O(o,e)),document.referrer&&(o=O(o,`utm_lastpage=${this.prepareLastPageUTM(document.referrer)}`),this.config.enableABTestTracking)){const t=new URL(document.referrer);t.searchParams.has("utm_id")&&(o=O(o,`utm_id=${t.searchParams.get("utm_id")}`))}t.href=o}return o=this.abTestManager.applyABTestToDownloadLink(o,e),t.href=o,x.log("[DownloadLinkEnhancer] Download link enhanced",{href:t.href,hasClassification:!!e}),t},this.enhanceAllDownloadLinks=()=>{if(/\/thanks/.test(window.location.pathname))return;const t=j(window.location.search);if(this.trafficClassifier.hasUTMTriplet(t)){const t=this.trafficClassifier.resolveClassification(document.referrer),r=W.generateParams(t),e=document.querySelectorAll(".download-button--wrapper a.button");let n=0;e.forEach(t=>{if(t.href&&/\/thanks/.test(t.href)){const e=new URL(t.href,window.location.origin);e.searchParams.has("utm_source")||e.searchParams.has("utm_medium")||e.searchParams.has("utm_campaign")||(t.href=O(t.href,r),n++)}}),x.log("[DownloadLinkEnhancer] Bulk enhancement complete",{totalLinks:e.length,enhancedLinks:n,hasUTMTriplet:!0})}},this.config={isGX:n.isGX??!1,enableABTestTracking:n.enableABTestTracking??!1}}prepareLastPageUTM(t){let e=T(t).host,n=T(t).pathname;return n=this.config.isGX?n.replace(ft.LOCALE_REGEX_GX,"/"):n.replace(ft.LOCALE_REGEX_MAIN,"/"),e=e.replace("www.",r),e+n||"undefined"}extendParamsWithEditionParam(t){let r=t;for(const e of lt)if(e.sourcePattern.test(t)){if(!e.campaignPattern){r=O(t,`edition=${e.edition}`);break}if(e.campaignPattern.test(t)){r=O(t,`edition=${e.edition}`);break}}return r}}ft.LOCALE_REGEX_GX=/^\/(\w{2}(-\w{2,3})?(\/+|$))?/,ft.LOCALE_REGEX_MAIN=/^\/(?!gx\b)(\w{2}(-\w{2,3})?)(\/+|$)/;const ht={whatsapp:{paramName:"abid",paramValue:"whatsapp",variant:"ni_custom_whatsapp2_test",targetDomain:/net\.geo\.opera\.com/,requiredClassification:{medium:F.PAID,source:G.PAID}},vpn:{paramName:"abid",paramValue:"vpn",variants:["ni_custom_vpn_test","ni_custom_vpn_reference"],distribution:.5,targetDomain:/net\.geo\.opera\.com/,requiredClassification:{medium:F.PAID,source:G.PAID}}};class dt{applyABTestToDownloadLink(t,r){let e=t;if(!/net\.geo\.opera\.com/.test(t))return e;if(!r)return e;for(const n in ht){const o=ht[n];if(this.shouldApplyTest(o,t,r)){const r=this.selectVariant(o);e=this.applyVariantToUrl(e,r),x.log("[ABTestManager] A/B test applied",{testName:n,variant:r,originalUrl:t,modifiedUrl:e}),this.dispatchABTestEvent(n,r);break}}return e}shouldApplyTest(t,r,e){const n=new URLSearchParams(window.location.search);return!!n.has(t.paramName)&&n.get(t.paramName)===t.paramValue&&!!t.targetDomain.test(r)&&e.medium===t.requiredClassification.medium&&e.source===t.requiredClassification.source}selectVariant(t){if(t.variant)return t.variant;if(t.variants&&t.variants.length>0){const r=t.distribution??.5,e=Math.random();if(2===t.variants.length)return e>r?t.variants[0]:t.variants[1];const n=1/t.variants.length,o=Math.floor(e/n);return t.variants[Math.min(o,t.variants.length-1)]}return""}applyVariantToUrl(t,r){return r?t.replace(/utm_campaign=[^&]+/,`$&_${r}`):t}dispatchABTestEvent(t,r){const e=new CustomEvent("traffic:abtest:applied",{detail:{testName:t,variant:r,timestamp:Date.now()}});window.dispatchEvent(e)}}class vt{constructor(r={}){this.initializeDownloadLinkEnhancement=()=>{"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{this.enhanceAllDownloadLinks()}):this.enhanceAllDownloadLinks()},this.classifyTraffic=()=>{const t=this.shouldClassifyTraffic()?this.trafficClassifier.classify():this.getTrafficClassificationFromCookie(w(vt.COOKIE_NAME));return this.dispatchClassificationCompleteEvent(t),t},this.applyMobileTracking=(r,e)=>{if(r){const r=document.getElementsByTagName(t.ANCHOR);u()(v()(t=>(t.href=W.applyParamsToLink(t,e),t)))(r)}},this.applyTrackingForDownloadLink=t=>this.downloadLinkEnhancer.applyTrackingForDownloadLink(t),this.enhanceAllDownloadLinks=()=>{this.downloadLinkEnhancer.enhanceAllDownloadLinks();const t=new CustomEvent("traffic:download-enhancer:ready",{detail:{timestamp:Date.now()}});window.dispatchEvent(t)},this.getTrafficClassificationFromCookie=t=>this.cookieManager.getClassification(t),this.shouldClassifyTraffic=()=>!w(vt.COOKIE_NAME)||this.hasUTMTriplet(this.parameters),this.setTrafficClassificationToCookie=(t,r,e)=>{this.cookieManager.setClassification(t,r,e)},this.config={isGX:r.isGX??!1,enableABTestTracking:r.enableABTestTracking??!0},this.subName=I(a),this.domainFamily=A(o),this.parameters=j(window.location.search),this.cookieManager=new U(this.domainFamily),this.trafficClassifier=new ut(this.parameters,this.domainFamily,this.subName,o,this.cookieManager),this.abTestManager=new dt,this.downloadLinkEnhancer=new ft(this.cookieManager,this.trafficClassifier,this.abTestManager,{isGX:this.config.isGX,enableABTestTracking:this.config.enableABTestTracking}),this.initializeDownloadLinkEnhancement(),this.dispatchCoreLoadedEvent()}dispatchCoreLoadedEvent(){const t=new CustomEvent("traffic:core:loaded",{detail:{timestamp:Date.now()}});window.dispatchEvent(t)}dispatchClassificationCompleteEvent(t){const r=new CustomEvent("traffic:classification:complete",{detail:{classification:t,timestamp:Date.now()}});window.dispatchEvent(r)}resolveClassification(t){return this.trafficClassifier.resolveClassification(t)}hasUTMTriplet(t){return this.trafficClassifier.hasUTMTriplet(t)}hasGoogleAdsParams(t){return this.trafficClassifier.hasGoogleAdsParams(t)}}vt.UTM_REFERRER_KEY="utm_referrer",vt.COOKIE_NAME="opref";const gt=t=>(window.operaTrafficService=new vt(t),window.operaTrafficService),mt=(window.operaTrafficService?window.operaTrafficService:gt(),/\/gx(\/|$)/.test(window.location.pathname)||window.location.hostname.includes("gx.games")),yt=gt({isGX:mt,enableABTestTracking:!0});window.operaTrafficService=yt,x.log("[Tracking] Bundle loaded and ready",{isGX:mt});let _t=null;yt.shouldClassifyTraffic()&&(_t=yt.classifyTraffic(),x.log("[Tracking] Traffic classified immediately",{source:_t?.source,medium:_t?.medium})),window.addEventListener("DOMContentLoaded",()=>{if(window.innerWidth<768){const t=_t||yt.classifyTraffic(),r=W.generateParams(t);yt.applyMobileTracking(t,r),x.log("[Tracking] Mobile tracking applied",{source:t?.source,medium:t?.medium})}}),window.addEventListener("traffic:classify:request",()=>{yt.classifyTraffic()})})()})(); \ No newline at end of file diff --git a/crates/e2e/scenarios/real-web/opera.com.we b/crates/e2e/scenarios/real-web/opera.com.we index a4007ef..9ae7e93 100644 --- a/crates/e2e/scenarios/real-web/opera.com.we +++ b/crates/e2e/scenarios/real-web/opera.com.we @@ -31,6 +31,7 @@ cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/ma cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/runtime-homepage.6eaddfed41a8.js ../../real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/runtime-homepage.6eaddfed41a8.js text/javascript cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/vendors-homepage.f4c80b970c17.js ../../real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/vendors-homepage.f4c80b970c17.js text/javascript cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/mainHomepage.3c9e73f2cb32.js ../../real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/mainHomepage.3c9e73f2cb32.js text/javascript +cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js ../../real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/traffic.0f43603a9af9.js text/javascript cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/surveyMonkey.ad147daf8346.js ../../real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/surveyMonkey.ad147daf8346.js text/javascript cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/86139.5db06cb7fd3fc3f0637a.js ../../real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/86139.5db06cb7fd3fc3f0637a.js text/javascript cache_put opera https://cdn-production-opera-website.operacdn.com/staticfiles/49523.09dbd7863576ae781902.js ../../real-web/snapshots/opera.com/cdn-production-opera-website.operacdn.com/staticfiles/49523.09dbd7863576ae781902.js text/javascript diff --git a/crates/render/src/atlas.rs b/crates/render/src/atlas.rs index e675b7a..60903ee 100644 --- a/crates/render/src/atlas.rs +++ b/crates/render/src/atlas.rs @@ -377,6 +377,7 @@ impl GlyphAtlas { let render_px = size_px * scale; let shaped = font.shape_text(&line.text, size_px); let color = color_to_f32(&line.color); + let synthesize_bold = should_synthesize_bold(line, font); let mut quads = Vec::with_capacity(shaped.len()); @@ -425,12 +426,11 @@ impl GlyphAtlas { page: region.page, }); - if line.bold { - // Until the text pipeline selects real bold faces per run, - // approximate CSS bold by overstriking the glyph mask with a - // tiny horizontal offset. Advances stay unchanged, matching - // browser synthetic-bold behavior closely enough for fallback - // faces and web-font load failures. + if synthesize_bold { + // Approximate CSS bold by overstriking the glyph mask only + // when font resolution fell back to a non-bold face. Advances + // stay unchanged, matching browser synthetic-bold behavior for + // fallback faces and web-font load failures. let offset = synthetic_bold_offset(size_px); quads.push(TexturedQuad { x: gx + offset, @@ -451,6 +451,22 @@ impl GlyphAtlas { } } +fn should_synthesize_bold(line: &TextLine, font: &Font) -> bool { + line.bold && resolved_font_weight_class(font) < 600 +} + +fn resolved_font_weight_class(font: &Font) -> u16 { + if let Ok(os2) = font.os2() { + return os2.us_weight_class; + } + if let Ok(head) = font.head() { + if head.mac_style & 0x01 != 0 { + return 700; + } + } + 400 +} + fn synthetic_bold_offset(size_px: f32) -> f32 { (size_px * 0.0125).clamp(0.35, 0.9) } @@ -479,6 +495,7 @@ fn color_to_f32(c: &Color) -> [f32; 4] { mod tests { use super::*; use we_style::computed::TextDecoration; + use we_text::font::{Font, FontRegistry}; /// Create a fake glyph bitmap for testing. fn make_bitmap(w: u32, h: u32) -> GlyphBitmap { @@ -732,6 +749,64 @@ mod tests { ); } + #[test] + fn synthetic_bold_is_skipped_for_resolved_bold_face() { + let Some((regular, bold)) = regular_and_bold_system_faces() else { + return; + }; + + let mut line = text_line("AA", 0.0); + line.bold = true; + line.font_weight = 700.0; + + assert!(should_synthesize_bold(&line, ®ular)); + assert!(!should_synthesize_bold(&line, &bold)); + + let mut atlas = GlyphAtlas::with_page_size(512); + let regular_quads = atlas.build_text_quads(&line, ®ular, 1.0); + let bold_quads = atlas.build_text_quads(&line, &bold, 1.0); + + if regular_quads.is_empty() || bold_quads.is_empty() { + return; + } + assert_eq!( + regular_quads.len(), + bold_quads.len() * 2, + "fallback regular faces are overstruck, real bold faces are not" + ); + } + + fn regular_and_bold_system_faces() -> Option<(Font, Font)> { + let registry = FontRegistry::new(); + for family in registry.list_families() { + let Some(entries) = registry.family_entries(&family) else { + continue; + }; + let has_regular = entries + .iter() + .any(|entry| !entry.italic && entry.weight < 600); + let has_bold = entries + .iter() + .any(|entry| !entry.italic && entry.weight >= 600); + if !has_regular || !has_bold { + continue; + } + + let Some(regular) = registry.find_font_with_weight(&family, 400, false) else { + continue; + }; + let Some(bold) = registry.find_font_with_weight(&family, 700, false) else { + continue; + }; + if resolved_font_weight_class(®ular) < 600 + && resolved_font_weight_class(&bold) >= 600 + { + return Some((regular, bold)); + } + } + None + } + #[test] fn large_glyph_exceeding_page_creates_larger_page() { let mut atlas = GlyphAtlas::with_page_size(32); -- 2.51.2