Changeset 3734102
- Timestamp:
- 10/08/2026 09:17:45 AM (3 weeks ago)
- Location:
- post-views-counter/tags/1.8.0
- Files:
-
- 5 added
- 15 deleted
- 73 copied
-
. (copied) (copied from post-views-counter/trunk )
-
assets/chartjs/chart.min.css (deleted)
-
assets/chartjs/chart.min.js (copied) (copied from post-views-counter/trunk/assets/chartjs/chart.min.js ) (2 diffs)
-
assets/micromodal (copied) (copied from post-views-counter/trunk/assets/micromodal )
-
assets/microtip/microtip.css (deleted)
-
assets/microtip/microtip.min.css (copied) (copied from post-views-counter/trunk/assets/microtip/microtip.min.css )
-
blocks (copied) (copied from post-views-counter/trunk/blocks )
-
blocks/most-viewed-posts/block.json (copied) (copied from post-views-counter/trunk/blocks/most-viewed-posts/block.json )
-
blocks/most-viewed-posts/build (deleted)
-
blocks/most-viewed-posts/index.asset.php (copied) (copied from post-views-counter/trunk/blocks/most-viewed-posts/index.asset.php ) (1 diff)
-
blocks/most-viewed-posts/index.js (copied) (copied from post-views-counter/trunk/blocks/most-viewed-posts/index.js ) (1 diff)
-
blocks/most-viewed-posts/package-lock.json (deleted)
-
blocks/most-viewed-posts/package.json (deleted)
-
blocks/most-viewed-posts/src (deleted)
-
blocks/post-views/block.json (copied) (copied from post-views-counter/trunk/blocks/post-views/block.json )
-
blocks/post-views/build (deleted)
-
blocks/post-views/index.asset.php (copied) (copied from post-views-counter/trunk/blocks/post-views/index.asset.php )
-
blocks/post-views/index.js (copied) (copied from post-views-counter/trunk/blocks/post-views/index.js )
-
blocks/post-views/package-lock.json (deleted)
-
blocks/post-views/package.json (deleted)
-
blocks/post-views/src (deleted)
-
blocks/pro-placeholder (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder )
-
blocks/pro-placeholder/index.asset.php (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder/index.asset.php )
-
blocks/pro-placeholder/index.js (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder/index.js )
-
blocks/pro-placeholder/most-viewed-terms/block.json (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder/most-viewed-terms/block.json )
-
blocks/pro-placeholder/most-viewed-users/block.json (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder/most-viewed-users/block.json )
-
blocks/pro-placeholder/site-views/block.json (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder/site-views/block.json )
-
blocks/pro-placeholder/term-views/block.json (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder/term-views/block.json )
-
blocks/pro-placeholder/user-views/block.json (copied) (copied from post-views-counter/trunk/blocks/pro-placeholder/user-views/block.json )
-
css/admin-columns.css (copied) (copied from post-views-counter/trunk/css/admin-columns.css ) (1 diff)
-
css/admin-dashboard.css (copied) (copied from post-views-counter/trunk/css/admin-dashboard.css ) (1 diff)
-
css/admin-post.css (copied) (copied from post-views-counter/trunk/css/admin-post.css ) (1 diff)
-
css/admin-settings.css (copied) (copied from post-views-counter/trunk/css/admin-settings.css ) (1 diff)
-
css/admin.css (deleted)
-
css/block-editor-canvas.css (copied) (copied from post-views-counter/trunk/css/block-editor-canvas.css )
-
css/block-editor.css (copied) (copied from post-views-counter/trunk/css/block-editor.css ) (1 diff)
-
css/block-editor.min.css (deleted)
-
css/frontend.css (copied) (copied from post-views-counter/trunk/css/frontend.css ) (1 diff)
-
css/gutenberg.min.css (deleted)
-
css/page-reports.png (copied) (copied from post-views-counter/trunk/css/page-reports.png )
-
includes/class-admin.php (copied) (copied from post-views-counter/trunk/includes/class-admin.php ) (7 diffs)
-
includes/class-columns-modal.php (copied) (copied from post-views-counter/trunk/includes/class-columns-modal.php ) (6 diffs)
-
includes/class-columns.php (copied) (copied from post-views-counter/trunk/includes/class-columns.php ) (19 diffs)
-
includes/class-counter.php (copied) (copied from post-views-counter/trunk/includes/class-counter.php ) (49 diffs)
-
includes/class-crawler-detect.php (copied) (copied from post-views-counter/trunk/includes/class-crawler-detect.php )
-
includes/class-cron.php (copied) (copied from post-views-counter/trunk/includes/class-cron.php ) (3 diffs)
-
includes/class-dashboard-comparison.php (added)
-
includes/class-dashboard.php (copied) (copied from post-views-counter/trunk/includes/class-dashboard.php ) (23 diffs)
-
includes/class-emails-mailer.php (copied) (copied from post-views-counter/trunk/includes/class-emails-mailer.php ) (2 diffs)
-
includes/class-emails-period.php (copied) (copied from post-views-counter/trunk/includes/class-emails-period.php )
-
includes/class-emails-query.php (copied) (copied from post-views-counter/trunk/includes/class-emails-query.php ) (13 diffs)
-
includes/class-emails-scheduler.php (copied) (copied from post-views-counter/trunk/includes/class-emails-scheduler.php )
-
includes/class-emails-template.php (copied) (copied from post-views-counter/trunk/includes/class-emails-template.php )
-
includes/class-emails.php (copied) (copied from post-views-counter/trunk/includes/class-emails.php )
-
includes/class-entrances-eligibility.php (added)
-
includes/class-frontend.php (copied) (copied from post-views-counter/trunk/includes/class-frontend.php ) (5 diffs)
-
includes/class-functions.php (copied) (copied from post-views-counter/trunk/includes/class-functions.php ) (1 diff)
-
includes/class-import.php (copied) (copied from post-views-counter/trunk/includes/class-import.php ) (2 diffs)
-
includes/class-integration-gutenberg.php (copied) (copied from post-views-counter/trunk/includes/class-integration-gutenberg.php )
-
includes/class-integrations.php (copied) (copied from post-views-counter/trunk/includes/class-integrations.php )
-
includes/class-query.php (copied) (copied from post-views-counter/trunk/includes/class-query.php ) (10 diffs)
-
includes/class-settings-api.php (copied) (copied from post-views-counter/trunk/includes/class-settings-api.php ) (2 diffs)
-
includes/class-settings-display.php (copied) (copied from post-views-counter/trunk/includes/class-settings-display.php ) (10 diffs)
-
includes/class-settings-emails.php (copied) (copied from post-views-counter/trunk/includes/class-settings-emails.php ) (1 diff)
-
includes/class-settings-general.php (copied) (copied from post-views-counter/trunk/includes/class-settings-general.php )
-
includes/class-settings-integrations.php (copied) (copied from post-views-counter/trunk/includes/class-settings-integrations.php )
-
includes/class-settings-other.php (copied) (copied from post-views-counter/trunk/includes/class-settings-other.php )
-
includes/class-settings-reports.php (copied) (copied from post-views-counter/trunk/includes/class-settings-reports.php )
-
includes/class-settings.php (copied) (copied from post-views-counter/trunk/includes/class-settings.php ) (3 diffs)
-
includes/class-toolbar.php (copied) (copied from post-views-counter/trunk/includes/class-toolbar.php )
-
includes/class-traffic-signals.php (copied) (copied from post-views-counter/trunk/includes/class-traffic-signals.php ) (8 diffs)
-
includes/class-update.php (copied) (copied from post-views-counter/trunk/includes/class-update.php ) (2 diffs)
-
includes/class-visits-query.php (added)
-
includes/class-visits.php (added)
-
includes/class-widgets.php (copied) (copied from post-views-counter/trunk/includes/class-widgets.php )
-
includes/functions.php (copied) (copied from post-views-counter/trunk/includes/functions.php ) (19 diffs)
-
js/admin-columns.js (copied) (copied from post-views-counter/trunk/js/admin-columns.js ) (1 diff)
-
js/admin-dashboard.js (copied) (copied from post-views-counter/trunk/js/admin-dashboard.js ) (1 diff)
-
js/admin-post.js (copied) (copied from post-views-counter/trunk/js/admin-post.js ) (1 diff)
-
js/admin-quick-edit.js (copied) (copied from post-views-counter/trunk/js/admin-quick-edit.js ) (1 diff)
-
js/admin-settings.js (copied) (copied from post-views-counter/trunk/js/admin-settings.js ) (1 diff)
-
js/admin-theme.js (copied) (copied from post-views-counter/trunk/js/admin-theme.js )
-
js/admin-widgets.js (copied) (copied from post-views-counter/trunk/js/admin-widgets.js )
-
js/block-editor.js (copied) (copied from post-views-counter/trunk/js/block-editor.js ) (1 diff)
-
js/block-editor.min.js (deleted)
-
js/counter.js (copied) (copied from post-views-counter/trunk/js/counter.js )
-
js/frontend.js (copied) (copied from post-views-counter/trunk/js/frontend.js ) (1 diff)
-
js/gutenberg.min.js (deleted)
-
js/integration-gutenberg.js (copied) (copied from post-views-counter/trunk/js/integration-gutenberg.js )
-
js/metric-toggle.js (added)
-
languages/post-views-counter.pot (copied) (copied from post-views-counter/trunk/languages/post-views-counter.pot ) (1 diff)
-
post-views-counter.php (copied) (copied from post-views-counter/trunk/post-views-counter.php ) (23 diffs)
-
readme.txt (copied) (copied from post-views-counter/trunk/readme.txt ) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
post-views-counter/tags/1.8.0/assets/chartjs/chart.min.js
r3378305 r3734102 1 1 /*! 2 * Chart.js v4.5. 02 * Chart.js v4.5.1 3 3 * https://www.chartjs.org 4 4 * (c) 2025 Chart.js Contributors … … 11 11 * (c) 2023 Jukka Kurkela 12 12 * Released under the MIT License 13 */function _t(t){return t+.5|0}const yt=(t,e,i)=>Math.max(Math.min(t,i),e);function vt(t){return yt(_t(2.55*t),0,255)}function Mt(t){return yt(_t(255*t),0,255)}function wt(t){return yt(_t(t/2.55)/100,0,1)}function kt(t){return yt(_t(100*t),0,100)}const St={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Pt=[..."0123456789ABCDEF"],Dt=t=>Pt[15&t],Ct=t=>Pt[(240&t)>>4]+Pt[15&t],Ot=t=>(240&t)>>4==(15&t);function At(t){var e=(t=>Ot(t.r)&&Ot(t.g)&&Ot(t.b)&&Ot(t.a))(t)?Dt:Ct;return t?"#"+e(t.r)+e(t.g)+e(t.b)+((t,e)=>t<255?e(t):"")(t.a,e):void 0}const Tt=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Lt(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function Et(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function Rt(t,e,i){const s=Lt(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function It(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=function(t,e,i,s,n){return t===n?(e-i)/s+(e<i?6:0):e===n?(i-t)/s+2:(t-e)/s+4}(e,i,s,h,n),r=60*r+.5),[0|r,l||0,a]}function zt(t,e,i,s){return(Array.isArray(e)?t(e[0],e[1],e[2]):t(e,i,s)).map(Mt)}function Ft(t,e,i){return zt(Lt,t,e,i)}function Vt(t){return(t%360+360)%360}function Bt(t){const e=Tt.exec(t);let i,s=255;if(!e)return;e[5]!==i&&(s=e[6]?vt(+e[5]):Mt(+e[5]));const n=Vt(+e[2]),o=+e[3]/100,a=+e[4]/100;return i="hwb"===e[1]?function(t,e,i){return zt(Rt,t,e,i)}(n,o,a):"hsv"===e[1]?function(t,e,i){return zt(Et,t,e,i)}(n,o,a):Ft(n,o,a),{r:i[0],g:i[1],b:i[2],a:s}}const Wt={x:"dark",Z:"light",Y:"re",X:"blu",W:"gr",V:"medium",U:"slate",A:"ee",T:"ol",S:"or",B:"ra",C:"lateg",D:"ights",R:"in",Q:"turquois",E:"hi",P:"ro",O:"al",N:"le",M:"de",L:"yello",F:"en",K:"ch",G:"arks",H:"ea",I:"ightg",J:"wh"},Nt={OiceXe:"f0f8ff",antiquewEte:"faebd7",aqua:"ffff",aquamarRe:"7fffd4",azuY:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"0",blanKedOmond:"ffebcd",Xe:"ff",XeviTet:"8a2be2",bPwn:"a52a2a",burlywood:"deb887",caMtXe:"5f9ea0",KartYuse:"7fff00",KocTate:"d2691e",cSO:"ff7f50",cSnflowerXe:"6495ed",cSnsilk:"fff8dc",crimson:"dc143c",cyan:"ffff",xXe:"8b",xcyan:"8b8b",xgTMnPd:"b8860b",xWay:"a9a9a9",xgYF:"6400",xgYy:"a9a9a9",xkhaki:"bdb76b",xmagFta:"8b008b",xTivegYF:"556b2f",xSange:"ff8c00",xScEd:"9932cc",xYd:"8b0000",xsOmon:"e9967a",xsHgYF:"8fbc8f",xUXe:"483d8b",xUWay:"2f4f4f",xUgYy:"2f4f4f",xQe:"ced1",xviTet:"9400d3",dAppRk:"ff1493",dApskyXe:"bfff",dimWay:"696969",dimgYy:"696969",dodgerXe:"1e90ff",fiYbrick:"b22222",flSOwEte:"fffaf0",foYstWAn:"228b22",fuKsia:"ff00ff",gaRsbSo:"dcdcdc",ghostwEte:"f8f8ff",gTd:"ffd700",gTMnPd:"daa520",Way:"808080",gYF:"8000",gYFLw:"adff2f",gYy:"808080",honeyMw:"f0fff0",hotpRk:"ff69b4",RdianYd:"cd5c5c",Rdigo:"4b0082",ivSy:"fffff0",khaki:"f0e68c",lavFMr:"e6e6fa",lavFMrXsh:"fff0f5",lawngYF:"7cfc00",NmoncEffon:"fffacd",ZXe:"add8e6",ZcSO:"f08080",Zcyan:"e0ffff",ZgTMnPdLw:"fafad2",ZWay:"d3d3d3",ZgYF:"90ee90",ZgYy:"d3d3d3",ZpRk:"ffb6c1",ZsOmon:"ffa07a",ZsHgYF:"20b2aa",ZskyXe:"87cefa",ZUWay:"778899",ZUgYy:"778899",ZstAlXe:"b0c4de",ZLw:"ffffe0",lime:"ff00",limegYF:"32cd32",lRF:"faf0e6",magFta:"ff00ff",maPon:"800000",VaquamarRe:"66cdaa",VXe:"cd",VScEd:"ba55d3",VpurpN:"9370db",VsHgYF:"3cb371",VUXe:"7b68ee",VsprRggYF:"fa9a",VQe:"48d1cc",VviTetYd:"c71585",midnightXe:"191970",mRtcYam:"f5fffa",mistyPse:"ffe4e1",moccasR:"ffe4b5",navajowEte:"ffdead",navy:"80",Tdlace:"fdf5e6",Tive:"808000",TivedBb:"6b8e23",Sange:"ffa500",SangeYd:"ff4500",ScEd:"da70d6",pOegTMnPd:"eee8aa",pOegYF:"98fb98",pOeQe:"afeeee",pOeviTetYd:"db7093",papayawEp:"ffefd5",pHKpuff:"ffdab9",peru:"cd853f",pRk:"ffc0cb",plum:"dda0dd",powMrXe:"b0e0e6",purpN:"800080",YbeccapurpN:"663399",Yd:"ff0000",Psybrown:"bc8f8f",PyOXe:"4169e1",saddNbPwn:"8b4513",sOmon:"fa8072",sandybPwn:"f4a460",sHgYF:"2e8b57",sHshell:"fff5ee",siFna:"a0522d",silver:"c0c0c0",skyXe:"87ceeb",UXe:"6a5acd",UWay:"708090",UgYy:"708090",snow:"fffafa",sprRggYF:"ff7f",stAlXe:"4682b4",tan:"d2b48c",teO:"8080",tEstN:"d8bfd8",tomato:"ff6347",Qe:"40e0d0",viTet:"ee82ee",JHt:"f5deb3",wEte:"ffffff",wEtesmoke:"f5f5f5",Lw:"ffff00",LwgYF:"9acd32"};let Ht;function jt(t){Ht||(Ht=function(){const t={},e=Object.keys(Nt),i=Object.keys(Wt);let s,n,o,a,r;for(s=0;s<e.length;s++){for(a=r=e[s],n=0;n<i.length;n++)o=i[n],r=r.replace(o,Wt[o]);o=parseInt(Nt[a],16),t[r]=[o>>16&255,o>>8&255,255&o]}return t}(),Ht.transparent=[0,0,0,0]);const e=Ht[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}const $t=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const Yt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,Ut=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4);function Xt(t,e,i){if(t){let s=It(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=Ft(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function qt(t,e){return t?Object.assign(e||{},t):t}function Kt(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=Mt(t[3]))):(e=qt(t,{r:0,g:0,b:0,a:1})).a=Mt(e.a),e}function Gt(t){return"r"===t.charAt(0)?function(t){const e=$t.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=e[8]?vt(t):yt(255*t,0,255)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?vt(i):yt(i,0,255)),s=255&(e[4]?vt(s):yt(s,0,255)),n=255&(e[6]?vt(n):yt(n,0,255)),{r:i,g:s,b:n,a:o}}}(t):Bt(t)}class Jt{constructor(t){if(t instanceof Jt)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=Kt(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*St[s[1]],g:255&17*St[s[2]],b:255&17*St[s[3]],a:5===o?17*St[s[4]]:255}:7!==o&&9!==o||(n={r:St[s[1]]<<4|St[s[2]],g:St[s[3]]<<4|St[s[4]],b:St[s[5]]<<4|St[s[6]],a:9===o?St[s[7]]<<4|St[s[8]]:255})),i=n||jt(t)||Gt(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=qt(this._rgb);return t&&(t.a=wt(t.a)),t}set rgb(t){this._rgb=Kt(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${wt(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):void 0;var t}hexString(){return this._valid?At(this._rgb):void 0}hslString(){return this._valid?function(t){if(!t)return;const e=It(t),i=e[0],s=kt(e[1]),n=kt(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${wt(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):void 0}mix(t,e){if(t){const i=this.rgb,s=t.rgb;let n;const o=e===n?.5:e,a=2*o-1,r=i.a-s.a,l=((a*r==-1?a:(a+r)/(1+a*r))+1)/2;n=1-l,i.r=255&l*i.r+n*s.r+.5,i.g=255&l*i.g+n*s.g+.5,i.b=255&l*i.b+n*s.b+.5,i.a=o*i.a+(1-o)*s.a,this.rgb=i}return this}interpolate(t,e){return t&&(this._rgb=function(t,e,i){const s=Ut(wt(t.r)),n=Ut(wt(t.g)),o=Ut(wt(t.b));return{r:Mt(Yt(s+i*(Ut(wt(e.r))-s))),g:Mt(Yt(n+i*(Ut(wt(e.g))-n))),b:Mt(Yt(o+i*(Ut(wt(e.b))-o))),a:t.a+i*(e.a-t.a)}}(this._rgb,t._rgb,e)),this}clone(){return new Jt(this.rgb)}alpha(t){return this._rgb.a=Mt(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=_t(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return Xt(this._rgb,2,t),this}darken(t){return Xt(this._rgb,2,-t),this}saturate(t){return Xt(this._rgb,1,t),this}desaturate(t){return Xt(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=It(t);i[0]=Vt(i[0]+e),i=Ft(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function Zt(t){if(t&&"object"==typeof t){const e=t.toString();return"[object CanvasPattern]"===e||"[object CanvasGradient]"===e}return!1}function Qt(t){return Zt(t)?t:new Jt(t)}function te(t){return Zt(t)?t:new Jt(t).saturate(.5).darken(.1).hexString()}const ee=["x","y","borderWidth","radius","tension"],ie=["color","borderColor","backgroundColor"];const se=new Map;function ne(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=se.get(i);return s||(s=new Intl.NumberFormat(t,e),se.set(i,s)),s}(e,i).format(t)}const oe={values:t=>n(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=z(Math.abs(o)),r=isNaN(a)?1:Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),ne(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=i[e].significand||t/Math.pow(10,Math.floor(z(t)));return[1,2,3,5,10,15].includes(s)||e>.8*i.length?oe.numeric.call(this,t,e,i):""}};var ae={formatters:oe};const re=Object.create(null),le=Object.create(null);function he(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;e<s;++e){const s=i[e];t=t[s]||(t[s]=Object.create(null))}return t}function ce(t,e,i){return"string"==typeof e?x(he(t,e),i):x(he(t,""),e)}class de{constructor(t,e){this.animation=void 0,this.backgroundColor="rgba(0,0,0,0.1)",this.borderColor="rgba(0,0,0,0.1)",this.color="#666",this.datasets={},this.devicePixelRatio=t=>t.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>te(e.backgroundColor),this.hoverBorderColor=(t,e)=>te(e.borderColor),this.hoverColor=(t,e)=>te(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t),this.apply(e)}set(t,e){return ce(this,t,e)}get(t){return he(this,t)}describe(t,e){return ce(le,t,e)}override(t,e){return ce(re,t,e)}route(t,e,i,s){const n=he(this,t),a=he(this,i),r="_"+e;Object.defineProperties(n,{[r]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[r],e=a[s];return o(t)?Object.assign({},e,t):l(t,e)},set(t){this[r]=t}}})}apply(t){t.forEach((t=>t(this)))}}var ue=new de({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(t){t.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),t.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:t=>"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),t.set("animations",{colors:{type:"color",properties:ie},numbers:{type:"number",properties:ee}}),t.describe("animations",{_fallback:"animation"}),t.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}})},function(t){t.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(t){t.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(t,e)=>e.lineWidth,tickColor:(t,e)=>e.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:ae.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),t.route("scale.ticks","color","","color"),t.route("scale.grid","color","","borderColor"),t.route("scale.border","color","","borderColor"),t.route("scale.title","color","","color"),t.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t&&"dash"!==t}),t.describe("scales",{_fallback:"scale"}),t.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t})}]);function fe(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ge(t){let e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e}function pe(t,e,i){let s;return"string"==typeof t?(s=parseInt(t,10),-1!==t.indexOf("%")&&(s=s/100*e.parentNode[i])):s=t,s}const me=t=>t.ownerDocument.defaultView.getComputedStyle(t,null);function xe(t,e){return me(t).getPropertyValue(e)}const be=["top","right","bottom","left"];function _e(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=be[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}const ye=(t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot);function ve(t,e){if("native"in t)return t;const{canvas:i,currentDevicePixelRatio:s}=e,n=me(i),o="border-box"===n.boxSizing,a=_e(n,"padding"),r=_e(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.touches,s=i&&i.length?i[0]:t,{offsetX:n,offsetY:o}=s;let a,r,l=!1;if(ye(n,o,t.target))a=n,r=o;else{const t=e.getBoundingClientRect();a=s.clientX-t.left,r=s.clientY-t.top,l=!0}return{x:a,y:r,box:l}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const Me=t=>Math.round(10*t)/10;function we(t,e,i,s){const n=me(t),o=_e(n,"margin"),a=pe(n.maxWidth,t,"clientWidth")||T,r=pe(n.maxHeight,t,"clientHeight")||T,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=t&&ge(t);if(o){const t=o.getBoundingClientRect(),a=me(o),r=_e(a,"border","width"),l=_e(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=pe(a.maxWidth,o,"clientWidth"),n=pe(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||T,maxHeight:n||T}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=_e(n,"border","width"),e=_e(n,"padding");h-=e.width+t.width,c-=e.height+t.height}h=Math.max(0,h-o.width),c=Math.max(0,s?h/s:c-o.height),h=Me(Math.min(h,a,l.maxWidth)),c=Me(Math.min(c,r,l.maxHeight)),h&&!c&&(c=Me(h/2));return(void 0!==e||void 0!==i)&&s&&l.height&&c>l.height&&(c=l.height,h=Me(Math.floor(c*s))),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=M ath.floor(t.height*s),o=Math.floor(t.width*s);t.height=Math.floor(t.height),t.width=Math.floor(t.width);const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};fe()&&(window.addEventListener("test",null,e),window.removeEventListener("test",null,e))}catch(t){}return t}();function Pe(t,e){const i=xe(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t){return!t||s(t.size)||s(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Ce(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function Oe(t,e,i,s){let o=(s=s||{}).data=s.data||{},a=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(o=s.data={},a=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let r=0;const l=i.length;let h,c,d,u,f;for(h=0;h<l;h++)if(u=i[h],null==u||n(u)){if(n(u))for(c=0,d=u.length;c<d;c++)f=u[c],null==f||n(f)||(r=Ce(t,o,a,r,f))}else r=Ce(t,o,a,r,u);t.restore();const g=a.length/2;if(g>i.length){for(h=0;h<g;h++)delete o[a[h]];a.splice(0,g)}return r}function Ae(t,e,i){const s=t.currentDevicePixelRatio,n=0!==i?Math.max(i/2,.5):0;return Math.round((e-n)*s)/s+n}function Te(t,e){(e||t)&&((e=e||t.getContext("2d")).save(),e.resetTransform(),e.clearRect(0,0,t.width,t.height),e.restore())}function Le(t,e,i,s){Ee(t,e,i,s,null)}function Ee(t,e,i,s,n){let o,a,r,l,h,c,d,u;const f=e.pointStyle,g=e.rotation,p=e.radius;let m=(g||0)*L;if(f&&"object"==typeof f&&(o=f.toString(),"[object HTMLImageElement]"===o||"[object HTMLCanvasElement]"===o))return t.save(),t.translate(i,s),t.rotate(m),t.drawImage(f,-f.width/2,-f.height/2,f.width,f.height),void t.restore();if(!(isNaN(p)||p<=0)){switch(t.beginPath(),f){default:n?t.ellipse(i,s,n/2,p,0,0,O):t.arc(i,s,p,0,O),t.closePath();break;case"triangle":c=n?n/2:p,t.moveTo(i+Math.sin(m)*c,s-Math.cos(m)*p),m+=I,t.lineTo(i+Math.sin(m)*c,s-Math.cos(m)*p),m+=I,t.lineTo(i+Math.sin(m)*c,s-Math.cos(m)*p),t.closePath();break;case"rectRounded":h=.516*p,l=p-h,a=Math.cos(m+R)*l,d=Math.cos(m+R)*(n?n/2-h:l),r=Math.sin(m+R)*l,u=Math.sin(m+R)*(n?n/2-h:l),t.arc(i-d,s-r,h,m-C,m-E),t.arc(i+u,s-a,h,m-E,m),t.arc(i+d,s+r,h,m,m+E),t.arc(i-u,s+a,h,m+E,m+C),t.closePath();break;case"rect":if(!g){l=Math.SQRT1_2*p,c=n?n/2:l,t.rect(i-c,s-l,2*c,2*l);break}m+=R;case"rectRot":d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+u,s-a),t.lineTo(i+d,s+r),t.lineTo(i-u,s+a),t.closePath();break;case"crossRot":m+=R;case"cross":d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+d,s+r),t.moveTo(i+u,s-a),t.lineTo(i-u,s+a);break;case"star":d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+d,s+r),t.moveTo(i+u,s-a),t.lineTo(i-u,s+a),m+=R,d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+d,s+r),t.moveTo(i+u,s-a),t.lineTo(i-u,s+a);break;case"line":a=n?n/2:Math.cos(m)*p,r=Math.sin(m)*p,t.moveTo(i-a,s-r),t.lineTo(i+a,s+r);break;case"dash":t.moveTo(i,s),t.lineTo(i+Math.cos(m)*(n?n/2:p),s+Math.sin(m)*p);break;case!1:t.closePath()}t.fill(),e.borderWidth>0&&t.stroke()}}function Re(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.x<e.right+i&&t.y>e.top-i&&t.y<e.bottom+i}function Ie(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()}function ze(t){t.restore()}function Fe(t,e,i,s,n){if(!e)return t.lineTo(i.x,i.y);if("middle"===n){const s=(e.x+i.x)/2;t.lineTo(s,e.y),t.lineTo(s,i.y)}else"after"===n!=!!s?t.lineTo(e.x,i.y):t.lineTo(i.x,e.y);t.lineTo(i.x,i.y)}function Ve(t,e,i,s){if(!e)return t.lineTo(i.x,i.y);t.bezierCurveTo(s?e.cp1x:e.cp2x,s?e.cp1y:e.cp2y,s?i.cp2x:i.cp1x,s?i.cp2y:i.cp1y,i.x,i.y)}function Be(t,e,i,s,n){if(n.strikethrough||n.underline){const o=t.measureText(s),a=e-o.actualBoundingBoxLeft,r=e+o.actualBoundingBoxRight,l=i-o.actualBoundingBoxAscent,h=i+o.actualBoundingBoxDescent,c=n.strikethrough?(l+h)/2:h;t.strokeStyle=t.fillStyle,t.beginPath(),t.lineWidth=n.decorationWidth||2,t.moveTo(a,c),t.lineTo(r,c),t.stroke()}}function We(t,e){const i=t.fillStyle;t.fillStyle=e.color,t.fillRect(e.left,e.top,e.width,e.height),t.fillStyle=i}function Ne(t,e,i,o,a,r={}){const l=n(e)?e:[e],h=r.strokeWidth>0&&""!==r.strokeColor;let c,d;for(t.save(),t.font=a.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]),s(e.rotation)||t.rotate(e.rotation),e.color&&(t.fillStyle=e.color),e.textAlign&&(t.textAlign=e.textAlign),e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,r),c=0;c<l.length;++c)d=l[c],r.backdrop&&We(t,r.backdrop),h&&(r.strokeColor&&(t.strokeStyle=r.strokeColor),s(r.strokeWidth)||(t.lineWidth=r.strokeWidth),t.strokeText(d,i,o,r.maxWidth)),t.fillText(d,i,o,r.maxWidth),Be(t,i,o,d,r),o+=Number(a.lineHeight);t.restore()}function He(t,e){const{x:i,y:s,w:n,h:o,radius:a}=e;t.arc(i+a.topLeft,s+a.topLeft,a.topLeft,1.5*C,C,!0),t.lineTo(i,s+o-a.bottomLeft),t.arc(i+a.bottomLeft,s+o-a.bottomLeft,a.bottomLeft,C,E,!0),t.lineTo(i+n-a.bottomRight,s+o),t.arc(i+n-a.bottomRight,s+o-a.bottomRight,a.bottomRight,E,0,!0),t.lineTo(i+n,s+a.topRight),t.arc(i+n-a.topRight,s+a.topRight,a.topRight,0,-E,!0),t.lineTo(i+a.topLeft,s)}function je(t,e=[""],i,s,n=(()=>t[0])){const o=i||t;void 0===s&&(s=ti("_fallback",t));const a={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:o,_fallback:s,_getTarget:n,override:i=>je([i,...t],e,o,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>qe(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=ti(Ue(o,t),i),void 0!==n)return Xe(t,n)?Ze(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>ei(t).includes(e),ownKeys:t=>ei(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function $e(t,e,i,s){const a={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:Ye(t,s),setContext:e=>$e(t,e,i,s),override:n=>$e(t.override(n),e,i,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>qe(t,e,(()=>function(t,e,i){const{_proxy:s,_context:a,_subProxy:r,_descriptors:l}=t;let h=s[e];S(h)&&l.isScriptable(e)&&(h=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t);let l=e(o,a||s);r.delete(t),Xe(t,l)&&(l=Ze(n._scopes,n,t,l));return l}(e,h,t,i));n(h)&&h.length&&(h=function(t,e,i,s){const{_proxy:n,_context:a,_subProxy:r,_descriptors:l}=i;if(void 0!==a.index&&s(t))return e[a.index%e.length];if(o(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const o of i){const i=Ze(s,n,t,o);e.push($e(i,a,r&&r[t],l))}}return e}(e,h,t,l.isIndexable));Xe(e,h)&&(h=$e(h,a,r&&r[e],l));return h}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function Ye(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:S(i)?i:()=>i,isIndexable:S(s)?s:()=>s}}const Ue=(t,e)=>t?t+w(e):e,Xe=(t,e)=>o(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function qe(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e)||"constructor"===e)return t[e];const s=i();return t[e]=s,s}function Ke(t,e,i){return S(t)?t(e,i):t}const Ge=(t,e)=>!0===t?e:"string"==typeof t?M(e,t):void 0;function Je(t,e,i,s,n){for(const o of e){const e=Ge(i,o);if(e){t.add(e);const o=Ke(e._fallback,i,n);if(void 0!==o&&o!==i&&o!==s)return o}else if(!1===e&&void 0!==s&&i!==s)return null}return!1}function Ze(t,e,i,s){const a=e._rootScopes,r=Ke(e._fallback,i,s),l=[...t,...a],h=new Set;h.add(s);let c=Qe(h,l,i,r||i,s);return null!==c&&((void 0===r||r===i||(c=Qe(h,l,r,c,s),null!==c))&&je(Array.from(h),[""],a,r,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const a=s[e];if(n(a)&&o(i))return i;return a||{}}(e,i,s))))}function Qe(t,e,i,s,n){for(;i;)i=Je(t,e,i,s,n);return i}function ti(t,e){for(const i of e){if(!i)continue;const e=i[t];if(void 0!==e)return e}}function ei(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}function ii(t,e,i,s){const{iScale:n}=t,{key:o="r"}=this._parsing,a=new Array(s);let r,l,h,c;for(r=0,l=s;r<l;++r)h=r+i,c=e[h],a[r]={r:n.parse(M(c,o),h)};return a}const si=Number.EPSILON||1e-14,ni=(t,e)=>e<t.length&&!t[e].skip&&t[e],oi=t=>"x"===t?"y":"x";function ai(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=q(o,n),l=q(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function ri(t,e="x"){const i=oi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=ni(t,0);for(a=0;a<s;++a)if(r=l,l=h,h=ni(t,a+1),l){if(h){const t=h[e]-l[e];n[a]=0!==t?(h[i]-l[i])/t:0}o[a]=r?h?F(n[a-1])!==F(n[a])?0:(n[a-1]+n[a])/2:n[a-1]:n[a]}!function(t,e,i){const s=t.length;let n,o,a,r,l,h=ni(t,0);for(let c=0;c<s-1;++c)l=h,h=ni(t,c+1),l&&h&&(V(e[c],0,si)?i[c]=i[c+1]=0:(n=i[c]/e[c],o=i[c+1]/e[c],r=Math.pow(n,2)+Math.pow(o,2),r<=9||(a=3/Math.sqrt(r),i[c]=n*a*e[c],i[c+1]=o*a*e[c])))}(t,n,o),function(t,e,i="x"){const s=oi(i),n=t.length;let o,a,r,l=ni(t,0);for(let h=0;h<n;++h){if(a=r,r=l,l=ni(t,h+1),!r)continue;const n=r[i],c=r[s];a&&(o=(n-a[i])/3,r[`cp1${i}`]=n-o,r[`cp1${s}`]=c-o*e[h]),l&&(o=(l[i]-n)/3,r[`cp2${i}`]=n+o,r[`cp2${s}`]=c+o*e[h])}}(t,o,e)}function li(t,e,i){return Math.max(Math.min(t,i),e)}function hi(t,e,i,s,n){let o,a,r,l;if(e.spanGaps&&(t=t.filter((t=>!t.skip))),"monotone"===e.cubicInterpolationMode)ri(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o<a;++o)r=t[o],l=ai(i,r,t[Math.min(o+1,a-(s?0:1))%a],e.tension),r.cp1x=l.previous.x,r.cp1y=l.previous.y,r.cp2x=l.next.x,r.cp2y=l.next.y,i=r}e.capBezierPoints&&function(t,e){let i,s,n,o,a,r=Re(t[0],e);for(i=0,s=t.length;i<s;++i)a=o,o=r,r=i<s-1&&Re(t[i+1],e),o&&(n=t[i],a&&(n.cp1x=li(n.cp1x,e.left,e.right),n.cp1y=li(n.cp1y,e.top,e.bottom)),r&&(n.cp2x=li(n.cp2x,e.left,e.right),n.cp2y=li(n.cp2y,e.top,e.bottom)))}(t,i)}const ci=t=>0===t||1===t,di=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*O/i),ui=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*O/i)+1,fi={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*E),easeOutSine:t=>Math.sin(t*E),easeInOutSine:t=>-.5*(Math.cos(C*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>ci(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>ci(t)?t:di(t,.075,.3),easeOutElastic:t=>ci(t)?t:ui(t,.075,.3),easeInOutElastic(t){const e=.1125;return ci(t)?t:t<.5?.5*di(2*t,e,.45):.5+.5*ui(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-fi.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*fi.easeInBounce(2*t):.5*fi.easeOutBounce(2*t-1)+.5};function gi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function pi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function mi(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=gi(t,n,i),r=gi(n,o,i),l=gi(o,e,i),h=gi(a,r,i),c=gi(r,l,i);return gi(h,c,i)}const xi=/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/,bi=/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;function _i(t,e){const i=(""+t).match(xi);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}const yi=t=>+t||0;function vi(t,e){const i={},s=o(e),n=s?Object.keys(e):e,a=o(t)?s?i=>l(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=yi(a(t));return i}function Mi(t){return vi(t,{top:"y",right:"x",bottom:"y",left:"x"})}function wi(t){return vi(t,["topLeft","topRight","bottomLeft","bottomRight"])}function ki(t){const e=Mi(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function Si(t,e){t=t||{},e=e||ue.font;let i=l(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=l(t.style,e.style);s&&!(""+s).match(bi)&&(console.warn('Invalid font style specified: "'+s+'"'),s=void 0);const n={family:l(t.family,e.family),lineHeight:_i(l(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:l(t.weight,e.weight),string:""};return n.string=De(n),n}function Pi(t,e,i,s){let o,a,r,l=!0;for(o=0,a=t.length;o<a;++o)if(r=t[o],void 0!==r&&(void 0!==e&&"function"==typeof r&&(r=r(e),l=!1),void 0!==i&&n(r)&&(r=r[i%r.length],l=!1),void 0!==r))return s&&!l&&(s.cacheable=!1),r}function Di(t,e,i){const{min:s,max:n}=t,o=c(e,(n-s)/2),a=(t,e)=>i&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ci(t,e){return Object.assign(Object.create(t),e)}function Oi(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ai(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function Ti(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Li(t){return"angle"===t?{between:J,compare:K,normalize:G}:{between:tt,compare:(t,e)=>t-e,normalize:t=>t}}function Ei({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Ri(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Li(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Li(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;h<c&&a(r(e[d%l][s]),n,o);++h)d--,u--;d%=l,u%=l}return u<d&&(u+=l),{start:d,end:u,loop:f,style:t.style}}(t,e,i),g=[];let p,m,x,b=!1,_=null;const y=()=>b||l(n,x,p)&&0!==r(n,x),v=()=>!b||0===r(o,p)||l(o,x,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==x&&(b=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Ei({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,x=p));return null!==_&&g.push(Ei({start:_,end:d,loop:u,count:a,style:f})),g}function Ii(t,e){const i=[],s=t.segments;for(let n=0;n<s.length;n++){const o=Ri(s[n],t.points,e);o.length&&i.push(...o)}return i}function zi(t,e){const i=t.points,s=t.options.spanGaps,n=i.length;if(!n)return[];const o=!!t._loop,{start:a,end:r}=function(t,e,i,s){let n=0,o=e-1;if(i&&!s)for(;n<e&&!t[n].skip;)n++;for(;n<e&&t[n].skip;)n++;for(n%=e,i&&(o+=n);o>n&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Fi(t,[{start:a,end:r,loop:o}],i,e);return Fi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,r<a?r+n:r,!!t._fullLoop&&0===a&&r===n-1),i,e)}function Fi(t,e,i,s){return s&&s.setContext&&i?function(t,e,i,s){const n=t._chart.getContext(),o=Vi(t.options),{_datasetIndex:a,options:{spanGaps:r}}=t,l=i.length,h=[];let c=o,d=e[0].start,u=d;function f(t,e,s,n){const o=r?-1:1;if(t!==e){for(t+=l;i[t%l].skip;)t-=o;for(;i[e%l].skip;)e+=o;t%l!=e%l&&(h.push({start:t%l,end:e%l,loop:s,style:n}),c=n,d=e%l)}}for(const t of e){d=r?d:t.start;let e,o=i[d%l];for(u=d+1;u<=t.end;u++){const r=i[u%l];e=Vi(s.setContext(Ci(n,{type:"segment",p0:o,p1:r,p0DataIndex:(u-1)%l,p1DataIndex:u%l,datasetIndex:a}))),Bi(e,c)&&f(d,u-1,t.loop,c),o=r,c=e}d<u-1&&f(d,u-1,t.loop,c)}return h}(t,e,i,s):e}function Vi(t){return{backgroundColor:t.backgroundColor,borderCapStyle:t.borderCapStyle,borderDash:t.borderDash,borderDashOffset:t.borderDashOffset,borderJoinStyle:t.borderJoinStyle,borderWidth:t.borderWidth,borderColor:t.borderColor}}function Bi(t,e){if(!e)return!1;const i=[],s=function(t,e){return Zt(e)?(i.includes(e)||i.push(e),i.indexOf(e)):e};return JSON.stringify(t,s)!==JSON.stringify(e,s)}function Wi(t,e,i){return t.options.clip?t[i]:e[i]}function Ni(t,e){const i=e._clip;if(i.disabled)return!1;const s=function(t,e){const{xScale:i,yScale:s}=t;return i&&s?{left:Wi(i,e,"left"),right:Wi(i,e,"right"),top:Wi(s,e,"top"),bottom:Wi(s,e,"bottom")}:e}(e,t.chartArea);return{left:!1===i.left?0:s.left-(!0===i.left?0:i.left),right:!1===i.right?t.width:s.right+(!0===i.right?0:i.right),top:!1===i.top?0:s.top-(!0===i.top?0:i.top),bottom:!1===i.bottom?t.height:s.bottom+(!0===i.bottom?0:i.bottom)}}var Hi=Object.freeze({__proto__:null,HALF_PI:E,INFINITY:T,PI:C,PITAU:A,QUARTER_PI:R,RAD_PER_DEG:L,TAU:O,TWO_THIRDS_PI:I,_addGrace:Di,_alignPixel:Ae,_alignStartEnd:ft,_angleBetween:J,_angleDiff:K,_arrayUnique:lt,_attachContext:$e,_bezierCurveTo:Ve,_bezierInterpolation:mi,_boundSegment:Ri,_boundSegments:Ii,_capitalize:w,_computeSegments:zi,_createResolver:je,_decimalPlaces:U,_deprecated:function(t,e,i,s){void 0!==e&&console.warn(t+': "'+i+'" is deprecated. Please use "'+s+'" instead')},_descriptors:Ye,_elementsEqual:f,_factorize:W,_filterBetween:nt,_getParentNode:ge,_getStartAndCountOfVisiblePoints:pt,_int16Range:Q,_isBetween:tt,_isClickEvent:D,_isDomSupported:fe,_isPointInArea:Re,_limitValue:Z,_longestText:Oe,_lookup:et,_lookupByKey:it,_measureText:Ce,_merger:m,_mergerIf:_,_normalizeAngle:G,_parseObjectDataRadialScale:ii,_pointInLine:gi,_readValueToProps:vi,_rlookupByKey:st,_scaleRangesChanged:mt,_setMinAndMaxByKey:j,_splitKey:v,_steppedInterpolation:pi,_steppedLineTo:Fe,_textX:gt,_toLeftRightCenter:ut,_updateBezierControlPoints:hi,addRoundedRectPath:He,almostEquals:V,almostWhole:H,callback:d,clearCanvas:Te,clipArea:Ie,clone:g,color:Qt,createContext:Ci,debounce:dt,defined:k,distanceBetweenPoints:q,drawPoint:Le,drawPointLegend:Ee,each:u,easingEffects:fi,finiteOrDefault:r,fontString:function(t,e,i){return e+" "+t+"px "+i},formatNumber:ne,getAngleFromPoint:X,getDatasetClipArea:Ni,getHoverColor:te,getMaximumSize:we,getRelativePosition:ve,getRtlAdapter:Oi,getStyle:xe,isArray:n,isFinite:a,isFunction:S,isNullOrUndef:s,isNumber:N,isObject:o,isPatternOrGradient:Zt,listenArrayEvents:at,log10:z,merge:x,mergeIf:b,niceNum:B,noop:e,overrideTextDirection:Ai,readUsedSize:Pe,renderText:Ne,requestAnimFrame:ht,resolve:Pi,resolveObjectKey:M,restoreTextDirection:Ti,retinaScale:ke,setsEqual:P,sign:F,splineCurve:ai,splineCurveMonotone:ri,supportsEventListenerOptions:Se,throttled:ct,toDegrees:Y,toDimension:c,toFont:Si,toFontString:De,toLineHeight:_i,toPadding:ki,toPercentage:h,toRadians:$,toTRBL:Mi,toTRBLCorners:wi,uid:i,unclipArea:ze,unlistenArrayEvents:rt,valueOrDefault:l});function ji(t,e,i,n){const{controller:o,data:a,_sorted:r}=t,l=o._cachedMeta.iScale,h=t.dataset&&t.dataset.options?t.dataset.options.spanGaps:null;if(l&&e===l.axis&&"r"!==e&&r&&a.length){const r=l._reversePixels?st:it;if(!n){const n=r(a,e,i);if(h){const{vScale:e}=o._cachedMeta,{_parsed:i}=t,a=i.slice(0,n.lo+1).reverse().findIndex((t=>!s(t[e.axis])));n.lo-=Math.max(0,a);const r=i.slice(n.hi).findIndex((t=>!s(t[e.axis])));n.hi+=Math.max(0,r)}return n}if(o._sharedOptions){const t=a[0],s="function"==typeof t.getRange&&t.getRange(e);if(s){const t=r(a,e,i-s),n=r(a,e,i+s);return{lo:t.lo,hi:n.hi}}}}return{lo:0,hi:a.length-1}}function $i(t,e,i,s,n){const o=t.getSortedVisibleDatasetMetas(),a=i[e];for(let t=0,i=o.length;t<i;++t){const{index:i,data:r}=o[t],{lo:l,hi:h}=ji(o[t],e,a,n);for(let t=l;t<=h;++t){const e=r[t];e.skip||s(e,i,t)}}}function Yi(t,e,i,s,n){const o=[];if(!n&&!t.isPointInArea(e))return o;return $i(t,i,e,(function(i,a,r){(n||Re(i,t.chartArea,0))&&i.inRange(e.x,e.y,s)&&o.push({element:i,datasetIndex:a,index:r})}),!0),o}function Ui(t,e,i,s,n,o){let a=[];const r=function(t){const e=-1!==t.indexOf("x"),i=-1!==t.indexOf("y");return function(t,s){const n=e?Math.abs(t.x-s.x):0,o=i?Math.abs(t.y-s.y):0;return Math.sqrt(Math.pow(n,2)+Math.pow(o,2))}}(i);let l=Number.POSITIVE_INFINITY;return $i(t,i,e,(function(i,h,c){const d=i.inRange(e.x,e.y,n);if(s&&!d)return;const u=i.getCenterPoint(n);if(!(!!o||t.isPointInArea(u))&&!d)return;const f=r(e,u);f<l?(a=[{element:i,datasetIndex:h,index:c}],l=f):f===l&&a.push({element:i,datasetIndex:h,index:c})})),a}function Xi(t,e,i,s,n,o){return o||t.isPointInArea(e)?"r"!==i||s?Ui(t,e,i,s,n,o):function(t,e,i,s){let n=[];return $i(t,i,e,(function(t,i,o){const{startAngle:a,endAngle:r}=t.getProps(["startAngle","endAngle"],s),{angle:l}=X(t,{x:e.x,y:e.y});J(l,a,r)&&n.push({element:t,datasetIndex:i,index:o})})),n}(t,e,i,n):[]}function qi(t,e,i,s,n){const o=[],a="x"===i?"inXRange":"inYRange";let r=!1;return $i(t,i,e,((t,s,l)=>{t[a]&&t[a](e[i],n)&&(o.push({element:t,datasetIndex:s,index:l}),r=r||t.inRange(e.x,e.y,n))})),s&&!r?[]:o}var Ki={evaluateInteractionItems:$i,modes:{index(t,e,i,s){const n=ve(e,t),o=i.axis||"x",a=i.includeInvisible||!1,r=i.intersect?Yi(t,n,o,s,a):Xi(t,n,o,!1,s,a),l=[];return r.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=r[0].index,i=t.data[e];i&&!i.skip&&l.push({element:i,datasetIndex:t.index,index:e})})),l):[]},dataset(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;let r=i.intersect?Yi(t,n,o,s,a):Xi(t,n,o,!1,s,a);if(r.length>0){const e=r[0].datasetIndex,i=t.getDatasetMeta(e).data;r=[];for(let t=0;t<i.length;++t)r.push({element:i[t],datasetIndex:e,index:t})}return r},point:(t,e,i,s)=>Yi(t,ve(e,t),i.axis||"xy",s,i.includeInvisible||!1),nearest(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;return Xi(t,n,o,i.intersect,s,a)},x:(t,e,i,s)=>qi(t,ve(e,t),"x",i.intersect,s),y:(t,e,i,s)=>qi(t,ve(e,t),"y",i.intersect,s)}};const Gi=["left","top","right","bottom"];function Ji(t,e){return t.filter((t=>t.pos===e))}function Zi(t,e){return t.filter((t=>-1===Gi.indexOf(t.pos)&&t.box.axis===e))}function Qi(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function ts(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!Gi.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o<a;++o){r=t[o];const{fullSize:a}=r.box,l=i[r.stack],h=l&&r.stackWeight/l.weight;r.horizontal?(r.width=h?h*s:a&&e.availableWidth,r.height=n):(r.width=s,r.height=h?h*n:a&&e.availableHeight)}return i}function es(t,e,i,s){return Math.max(t[i],e[i])+Math.max(t[s],e[s])}function is(t,e){t.top=Math.max(t.top,e.top),t.left=Math.max(t.left,e.left),t.bottom=Math.max(t.bottom,e.bottom),t.right=Math.max(t.right,e.right)}function ss(t,e,i,s){const{pos:n,box:a}=i,r=t.maxPadding;if(!o(n)){i.size&&(t[n]-=i.size);const e=s[i.stack]||{size:0,count:1};e.size=Math.max(e.size,i.horizontal?a.height:a.width),i.size=e.size/e.count,t[n]+=i.size}a.getPadding&&is(r,a.getPadding());const l=Math.max(0,e.outerWidth-es(r,t,"left","right")),h=Math.max(0,e.outerHeight-es(r,t,"top","bottom")),c=l!==t.w,d=h!==t.h;return t.w=l,t.h=h,i.horizontal?{same:c,other:d}:{same:d,other:c}}function ns(t,e){const i=e.maxPadding;function s(t){const s={left:0,top:0,right:0,bottom:0};return t.forEach((t=>{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function os(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;o<a;++o){r=t[o],l=r.box,l.update(r.width||e.w,r.height||e.h,ns(r.horizontal,e));const{same:a,other:d}=ss(e,i,r,s);h|=a&&n.length,c=c||d,l.fullSize||n.push(r)}return h&&os(n,e,i,s)||c}function as(t,e,i,s,n){t.top=i,t.left=e,t.right=e+s,t.bottom=i+n,t.width=s,t.height=n}function rs(t,e,i,s){const n=i.padding;let{x:o,y:a}=e;for(const r of t){const t=r.box,l=s[r.stack]||{count:1,placed:0,weight:1},h=r.stackWeight/l.weight||1;if(r.horizontal){const s=e.w*h,o=l.size||t.height;k(l.start)&&(a=l.start),t.fullSize?as(t,n.left,a,i.outerWidth-n.right-n.left,o):as(t,e.left+l.placed,a,s,o),l.start=a,l.placed+=s,a=t.bottom}else{const s=e.h*h,a=l.size||t.width;k(l.start)&&(o=l.start),t.fullSize?as(t,o,n.top,a,i.outerHeight-n.bottom-n.top):as(t,o,e.top+l.placed,a,s),l.start=o,l.placed+=s,o=t.right}}e.x=o,e.y=a}var ls={addBox(t,e){t.boxes||(t.boxes=[]),e.fullSize=e.fullSize||!1,e.position=e.position||"top",e.weight=e.weight||0,e._layers=e._layers||function(){return[{z:0,draw(t){e.draw(t)}}]},t.boxes.push(e)},removeBox(t,e){const i=t.boxes?t.boxes.indexOf(e):-1;-1!==i&&t.boxes.splice(i,1)},configure(t,e,i){e.fullSize=i.fullSize,e.position=i.position,e.weight=i.weight},update(t,e,i,s){if(!t)return;const n=ki(t.options.layout.padding),o=Math.max(e-n.width,0),a=Math.max(i-n.height,0),r=function(t){const e=function(t){const e=[];let i,s,n,o,a,r;for(i=0,s=(t||[]).length;i<s;++i)n=t[i],({position:o,options:{stack:a,stackWeight:r=1}}=n),e.push({index:i,box:n,pos:o,horizontal:n.isHorizontal(),weight:n.weight,stack:a&&o+a,stackWeight:r});return e}(t),i=Qi(e.filter((t=>t.box.fullSize)),!0),s=Qi(Ji(e,"left"),!0),n=Qi(Ji(e,"right")),o=Qi(Ji(e,"top"),!0),a=Qi(Ji(e,"bottom")),r=Zi(e,"x"),l=Zi(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Ji(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;u(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),f=Object.assign({},n);is(f,ki(s));const g=Object.assign({maxPadding:f,w:o,h:a,x:n.left,y:n.top},n),p=ts(l.concat(h),d);os(r.fullSize,g,d,p),os(l,g,d,p),os(h,g,d,p)&&os(l,g,d,p),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(g),rs(r.leftAndTop,g,d,p),g.x+=g.w,g.y+=g.h,rs(r.rightAndBottom,g,d,p),t.chartArea={left:g.left,top:g.top,right:g.left+g.w,bottom:g.top+g.h,height:g.h,width:g.w},u(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(g.w,g.h,{left:0,top:0,right:0,bottom:0})}))}};class hs{acquireContext(t,e){}releaseContext(t){return!1}addEventListener(t,e,i){}removeEventListener(t,e,i){}getDevicePixelRatio(){return 1}getMaximumSize(t,e,i,s){return e=Math.max(0,e||t.width),i=i||t.height,{width:e,height:Math.max(0,s?Math.floor(e/s):i)}}isAttached(t){return!0}updateConfig(t){}}class cs extends hs{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const ds="$chartjs",us={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},fs=t=>null===t||""===t;const gs=!!Se&&{passive:!0};function ps(t,e,i){t&&t.canvas&&t.canvas.removeEventListener(e,i,gs)}function ms(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function xs(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||ms(i.addedNodes,s),e=e&&!ms(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function bs(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||ms(i.removedNodes,s),e=e&&!ms(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const _s=new Map;let ys=0;function vs(){const t=window.devicePixelRatio;t!==ys&&(ys=t,_s.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function Ms(t,e,i){const s=t.canvas,n=s&&ge(s);if(!n)return;const o=ct(((t,e)=>{const s=n.clientWidth;i(t,e),s<n.clientWidth&&i()}),window),a=new ResizeObserver((t=>{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||o(i,s)}));return a.observe(n),function(t,e){_s.size||window.addEventListener("resize",vs),_s.set(t,e)}(t,o),a}function ws(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){_s.delete(t),_s.size||window.removeEventListener("resize",vs)}(t)}function ks(t,e,i){const s=t.canvas,n=ct((e=>{null!==t.ctx&&i(function(t,e){const i=us[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t);return function(t,e,i){t&&t.addEventListener(e,i,gs)}(s,e,n),n}class Ss extends hs{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t[ds]={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",fs(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(fs(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e[ds])return!1;const i=e[ds].initial;["height","width"].forEach((t=>{const n=i[t];s(n)?e.removeAttribute(t):e.setAttribute(t,n)}));const n=i.style||{};return Object.keys(n).forEach((t=>{e.style[t]=n[t]})),e.width=e.width,delete e[ds],!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:xs,detach:bs,resize:Ms}[e]||ks;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:ws,detach:ws,resize:ws}[e]||ps)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return we(t,e,i,s)}isAttached(t){const e=t&&ge(t);return!(!e||!e.isConnected)}}function Ps(t){return!fe()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?cs:Ss}var Ds=Object.freeze({__proto__:null,BasePlatform:hs,BasicPlatform:cs,DomPlatform:Ss,_detectPlatform:Ps});const Cs="transparent",Os={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=Qt(t||Cs),n=s.valid&&Qt(e||Cs);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class As{constructor(t,e,i,s){const n=e[i];s=Pi([t.to,s,n,t.from]);const o=Pi([t.from,n,s]);this._active=!0,this._fn=t.fn||Os[t.type||typeof o],this._easing=fi[t.easing]||fi.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=Pi([t.to,e,s,t.from]),this._from=Pi([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e<i),!this._active)return this._target[s]=a,void this._notify(!0);e<0?this._target[s]=n:(r=e/i%2,r=o&&r>1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t<i.length;t++)i[t][e]()}}class Ts{constructor(t,e){this._chart=t,this._properties=new Map,this.configure(e)}configure(t){if(!o(t))return;const e=Object.keys(ue.animation),i=this._properties;Object.getOwnPropertyNames(t).forEach((s=>{const a=t[s];if(!o(a))return;const r={};for(const t of e)r[t]=a[t];(n(a.properties)&&a.properties||[s]).forEach((t=>{t!==s&&i.has(t)||i.set(t,r)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e<s.length;e++){const n=t[s[e]];n&&n.active()&&i.push(n.wait())}return Promise.all(i)}(t.options.$animations,i).then((()=>{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new As(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(bt.add(this._chart,i),!0):void 0}}function Ls(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function Es(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n<o;++n)i.push(s[n].index);return i}function Rs(t,e,i,s={}){const n=t.keys,o="single"===s.mode;let r,l,h,c;if(null===e)return;let d=!1;for(r=0,l=n.length;r<l;++r){if(h=+n[r],h===i){if(d=!0,s.all)continue;break}c=t.values[h],a(c)&&(o||0===e||F(e)===F(c))&&(e+=c)}return d||s.all?e:0}function Is(t,e){const i=t&&t.options.stacked;return i||void 0===i&&void 0!==e.stack}function zs(t,e,i){const s=t[e]||(t[e]={});return s[i]||(s[i]={})}function Fs(t,e,i,s){for(const n of e.getMatchingVisibleMetas(s).reverse()){const e=t[n.index];if(i&&e>0||!i&&e<0)return n.index}return null}function Vs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;t<d;++t){const i=e[t],{[l]:o,[h]:d}=i;u=(i._stacks||(i._stacks={}))[h]=zs(n,c,o),u[r]=d,u._top=Fs(u,a,!0,s.type),u._bottom=Fs(u,a,!1,s.type);(u._visualValues||(u._visualValues={}))[r]=d}}function Bs(t,e){const i=t.scales;return Object.keys(i).filter((t=>i[t].axis===e)).shift()}function Ws(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i],void 0!==e[s]._visualValues&&void 0!==e[s]._visualValues[i]&&delete e[s]._visualValues[i]}}}const Ns=t=>"reset"===t||"none"===t,Hs=(t,e)=>e?t:Object.assign({},t);class js{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=Is(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&Ws(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=l(i.xAxisID,Bs(t,"x")),o=e.yAxisID=l(i.yAxisID,Bs(t,"y")),a=e.rAxisID=l(i.rAxisID,Bs(t,"r")),r=e.indexAxis,h=e.iAxisID=s(r,n,o,a),c=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(h),e.vScale=this.getScaleForId(c)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&rt(this._data,this),t._stacked&&Ws(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(o(e)){const t=this._cachedMeta;this._data=function(t,e){const{iScale:i,vScale:s}=e,n="x"===i.axis?"x":"y",o="x"===s.axis?"x":"y",a=Object.keys(t),r=new Array(a.length);let l,h,c;for(l=0,h=a.length;l<h;++l)c=a[l],r[l]={[n]:c,[o]:t[c]};return r}(e,t)}else if(i!==e){if(i){rt(i,this);const t=this._cachedMeta;Ws(t),t._parsed=[]}e&&Object.isExtensible(e)&&at(e,this),this._syncList=[],this._data=e}}addElements(){const t=this._cachedMeta;this._dataCheck(),this.datasetElementType&&(t.dataset=new this.datasetElementType)}buildOrUpdateElements(t){const e=this._cachedMeta,i=this.getDataset();let s=!1;this._dataCheck();const n=e._stacked;e._stacked=Is(e.vScale,e),e.stack!==i.stack&&(s=!0,Ws(e),e.stack=i.stack),this._resyncElements(t),(s||n!==e._stacked)&&(Vs(this,e._parsed),e._stacked=Is(e.vScale,e))}configure(){const t=this.chart.config,e=t.datasetScopeKeys(this._type),i=t.getOptionScopes(this.getDataset(),e,!0);this.options=t.createResolver(i,this.getContext()),this._parsing=this.options.parsing,this._cachedDataOpts={}}parse(t,e){const{_cachedMeta:i,_data:s}=this,{iScale:a,_stacked:r}=i,l=a.axis;let h,c,d,u=0===t&&e===s.length||i._sorted,f=t>0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,d=s;else{d=n(s[t])?this.parseArrayData(i,s,t,e):o(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const a=()=>null===c[l]||f&&c[l]<f[l];for(h=0;h<e;++h)i._parsed[h+t]=c=d[h],u&&(a()&&(u=!1),f=c);i._sorted=u}r&&Vs(this,d)}parsePrimitiveData(t,e,i,s){const{iScale:n,vScale:o}=t,a=n.axis,r=o.axis,l=n.getLabels(),h=n===o,c=new Array(s);let d,u,f;for(d=0,u=s;d<u;++d)f=d+i,c[d]={[a]:h||n.parse(l[f],f),[r]:o.parse(e[f],f)};return c}parseArrayData(t,e,i,s){const{xScale:n,yScale:o}=t,a=new Array(s);let r,l,h,c;for(r=0,l=s;r<l;++r)h=r+i,c=e[h],a[r]={x:n.parse(c[0],h),y:o.parse(c[1],h)};return a}parseObjectData(t,e,i,s){const{xScale:n,yScale:o}=t,{xAxisKey:a="x",yAxisKey:r="y"}=this._parsing,l=new Array(s);let h,c,d,u;for(h=0,c=s;h<c;++h)d=h+i,u=e[d],l[h]={x:n.parse(M(u,a),d),y:o.parse(M(u,r),d)};return l}getParsed(t){return this._cachedMeta._parsed[t]}getDataElement(t){return this._cachedMeta.data[t]}applyStack(t,e,i){const s=this.chart,n=this._cachedMeta,o=e[t.axis];return Rs({keys:Es(s,!0),values:e._stacks[t.axis]._visualValues},o,n.index,{mode:i})}updateRangeFromParsed(t,e,i,s){const n=i[e.axis];let o=null===n?NaN:n;const a=s&&i._stacks[e.axis];s&&a&&(s.values=a,o=Rs(s,n,this._cachedMeta.index)),t.min=Math.min(t.min,o),t.max=Math.max(t.max,o)}getMinMax(t,e){const i=this._cachedMeta,s=i._parsed,n=i._sorted&&t===i.iScale,o=s.length,r=this._getOtherScale(t),l=((t,e,i)=>t&&!e.hidden&&e._stacked&&{keys:Es(i,!0),values:null})(e,i,this.chart),h={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:c,max:d}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(r);let u,f;function g(){f=s[u];const e=f[r.axis];return!a(f[t.axis])||c>e||d<e}for(u=0;u<o&&(g()||(this.updateRangeFromParsed(h,t,f,l),!n));++u);if(n)for(u=o-1;u>=0;--u)if(!g()){this.updateRangeFromParsed(h,t,f,l);break}return h}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s<n;++s)o=e[s][t.axis],a(o)&&i.push(o);return i}getMaxOverflow(){return!1}getLabelAndValue(t){const e=this._cachedMeta,i=e.iScale,s=e.vScale,n=this.getParsed(t);return{label:i?""+i.getLabelForValue(n[i.axis]):"",value:s?""+s.getLabelForValue(n[s.axis]):""}}_update(t){const e=this._cachedMeta;this.update(t||"default"),e._clip=function(t){let e,i,s,n;return o(t)?(e=t.top,i=t.right,s=t.bottom,n=t.left):e=i=s=n=t,{top:e,right:i,bottom:s,left:n,disabled:!1===t}}(l(this.options.clip,function(t,e,i){if(!1===i)return!1;const s=Ls(t,i),n=Ls(e,i);return{top:n.end,right:s.end,bottom:n.start,left:s.start}}(e.xScale,e.yScale,this.getMaxOverflow())))}update(t){}draw(){const t=this._ctx,e=this.chart,i=this._cachedMeta,s=i.data||[],n=e.chartArea,o=[],a=this._drawStart||0,r=this._drawCount||s.length-a,l=this.options.drawActiveElementsOnTop;let h;for(i.dataset&&i.dataset.draw(t,n,a,r),h=a;h<a+r;++h){const e=s[h];e.hidden||(e.active&&l?o.push(e):e.draw(t,n))}for(h=0;h<o.length;++h)o[h].draw(t,n)}getStyle(t,e){const i=e?"active":"default";return void 0===t&&this._cachedMeta.dataset?this.resolveDatasetElementOptions(i):this.resolveDataElementOptions(t||0,i)}getContext(t,e,i){const s=this.getDataset();let n;if(t>=0&&t<this._cachedMeta.data.length){const e=this._cachedMeta.data[t];n=e.$context||(e.$context=function(t,e,i){return Ci(t,{active:!1,dataIndex:e,parsed:void 0,raw:void 0,element:i,index:e,mode:"default",type:"data"})}(this.getContext(),t,e)),n.parsed=this.getParsed(t),n.raw=s.data[t],n.index=n.dataIndex=t}else n=this.$context||(this.$context=function(t,e){return Ci(t,{active:!1,dataset:void 0,datasetIndex:e,index:e,mode:"default",type:"dataset"})}(this.chart.getContext(),this.index)),n.dataset=s,n.index=n.datasetIndex=this.index;return n.active=!!e,n.mode=i,n}resolveDatasetElementOptions(t){return this._resolveElementOptions(this.datasetElementType.id,t)}resolveDataElementOptions(t,e){return this._resolveElementOptions(this.dataElementType.id,e,t)}_resolveElementOptions(t,e="default",i){const s="active"===e,n=this._cachedDataOpts,o=t+"-"+e,a=n[o],r=this.enableOptionSharing&&k(i);if(a)return Hs(a,r);const l=this.chart.config,h=l.datasetElementScopeKeys(this._type,t),c=s?[`${t}Hover`,"hover",t,""]:[t,""],d=l.getOptionScopes(this.getDataset(),h),u=Object.keys(ue.elements[t]),f=l.resolveNamedOptions(d,u,(()=>this.getContext(i,s,e)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Hs(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new Ts(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||Ns(t)||this.chart._animationsDisabled}_getSharedOptions(t,e){const i=this.resolveDataElementOptions(t,e),s=this._sharedOptions,n=this.getSharedOptions(i),o=this.includeOptions(e,n)||n!==s;return this.updateSharedOptions(n,e,i),{sharedOptions:n,includeOptions:o}}updateElement(t,e,i,s){Ns(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!Ns(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n<s&&this._removeElements(n,s-n)}_insertElements(t,e,i=!0){const s=this._cachedMeta,n=s.data,o=t+e;let a;const r=t=>{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a<o;++a)n[a]=new this.dataElementType;this._parsing&&r(s._parsed),this.parse(t,e),i&&this.updateElements(n,t,e,"reset")}updateElements(t,e,i,s){}_removeElements(t,e){const i=this._cachedMeta;if(this._parsing){const s=i._parsed.splice(t,e);i._stacked&&Ws(i,s)}i.data.splice(t,e)}_sync(t){if(this._parsing)this._syncList.push(t);else{const[e,i,s]=t;this[e](i,s)}this.chart._dataChanges.push([this.index,...t])}_onDataPush(){const t=arguments.length;this._sync(["_insertElements",this.getDataset().data.length-t,t])}_onDataPop(){this._sync(["_removeElements",this._cachedMeta.data.length-1,1])}_onDataShift(){this._sync(["_removeElements",0,1])}_onDataSplice(t,e){e&&this._sync(["_removeElements",t,e]);const i=arguments.length-2;i&&this._sync(["_insertElements",t,i])}_onDataUnshift(){this._sync(["_insertElements",0,arguments.length])}}class $s{static defaults={};static defaultRoutes=void 0;x;y;active=!1;options;$animations;tooltipPosition(t){const{x:e,y:i}=this.getProps(["x","y"],t);return{x:e,y:i}}hasValue(){return N(this.x)&&N(this.y)}getProps(t,e){const i=this.$animations;if(!e||!i)return this;const s={};return t.forEach((t=>{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}function Ys(t,e){const i=t.options.ticks,n=function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),o=Math.min(i.maxTicksLimit||n,n),a=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;i<s;i++)t[i].major&&e.push(i);return e}(e):[],r=a.length,l=a[0],h=a[r-1],c=[];if(r>o)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;n<t.length;n++)n===a&&(e.push(t[n]),o++,a=i[o*s])}(e,c,a,r/o),c;const d=function(t,e,i){const s=function(t){const e=t.length;let i,s;if(e<2)return!1;for(s=t[0],i=1;i<e;++i)if(t[i]-t[i-1]!==s)return!1;return s}(t),n=e.length/i;if(!s)return Math.max(n,1);const o=W(s);for(let t=0,e=o.length-1;t<e;t++){const e=o[t];if(e>n)return e}return Math.max(n,1)}(a,e,o);if(r>0){let t,i;const n=r>1?Math.round((h-l)/(r-1)):null;for(Us(e,c,d,s(n)?0:l-n,l),t=0,i=r-1;t<i;t++)Us(e,c,d,a[t],a[t+1]);return Us(e,c,d,h,s(n)?e.length:h+n),c}return Us(e,c,d),c}function Us(t,e,i,s,n){const o=l(s,0),a=Math.min(l(n,t.length),t.length);let r,h,c,d=0;for(i=Math.ceil(i),n&&(r=n-s,i=r/Math.floor(r/i)),c=o;c<0;)d++,c=Math.round(o+d*i);for(h=Math.max(o,0);h<a;h++)h===c&&(e.push(t[h]),d++,c=Math.round(o+d*i))}const Xs=(t,e,i)=>"top"===e||"left"===e?t[e]+i:t[e]-i,qs=(t,e)=>Math.min(e||t,t);function Ks(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;o<n;o+=s)i.push(t[Math.floor(o)]);return i}function Gs(t,e,i){const s=t.ticks.length,n=Math.min(e,s-1),o=t._startPixel,a=t._endPixel,r=1e-6;let l,h=t.getPixelForTick(n);if(!(i&&(l=1===s?Math.max(h-o,a-h):0===e?(t.getPixelForTick(1)-h)/2:(h-t.getPixelForTick(n-1))/2,h+=n<e?l:-l,h<o-r||h>a+r)))return h}function Js(t){return t.drawTicks?t.tickLength:0}function Zs(t,e){if(!t.display)return 0;const i=Si(t.font,e),s=ki(t.padding);return(n(t.text)?t.text.length:1)*i.lineHeight+s.height}function Qs(t,e,i){let s=ut(t);return(i&&"right"!==e||!i&&"right"===e)&&(s=(t=>"left"===t?"right":"right"===t?"left":t)(s)),s}class tn extends $s{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=r(t,Number.POSITIVE_INFINITY),e=r(e,Number.NEGATIVE_INFINITY),i=r(i,Number.POSITIVE_INFINITY),s=r(s,Number.NEGATIVE_INFINITY),{min:r(t,i),max:r(e,s),minDefined:a(t),maxDefined:a(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;r<l;++r)e=a[r].controller.getMinMax(this,t),n||(i=Math.min(i,e.min)),o||(s=Math.max(s,e.max));return i=o&&i>s?s:i,s=n&&i>s?i:s,{min:r(i,r(s,i)),max:r(s,r(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=Di(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a<this.ticks.length;this._convertTicksToLabels(r?Ks(this.ticks,a):this.ticks),this.configure(),this.beforeCalculateLabelRotation(),this.calculateLabelRotation(),this.afterCalculateLabelRotation(),o.display&&(o.autoSkip||"auto"===o.source)&&(this.ticks=Ys(this,this.ticks),this._labelSizes=null,this.afterAutoSkip()),r&&this._convertTicksToLabels(this.ticks),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate()}configure(){let t,e,i=this.options.reverse;this.isHorizontal()?(t=this.left,e=this.right):(t=this.top,e=this.bottom,i=!i),this._startPixel=t,this._endPixel=e,this._reversePixels=i,this._length=e-t,this._alignToPixels=this.options.alignToPixels}afterUpdate(){d(this.options.afterUpdate,[this])}beforeSetDimensions(){d(this.options.beforeSetDimensions,[this])}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0}afterSetDimensions(){d(this.options.afterSetDimensions,[this])}_callHooks(t){this.chart.notifyPlugins(t,this.getContext()),d(this.options[t],[this])}beforeDataLimits(){this._callHooks("beforeDataLimits")}determineDataLimits(){}afterDataLimits(){this._callHooks("afterDataLimits")}beforeBuildTicks(){this._callHooks("beforeBuildTicks")}buildTicks(){return[]}afterBuildTicks(){this._callHooks("afterBuildTicks")}beforeTickToLabelConversion(){d(this.options.beforeTickToLabelConversion,[this])}generateTickLabels(t){const e=this.options.ticks;let i,s,n;for(i=0,s=t.length;i<s;i++)n=t[i],n.label=d(e.callback,[n.value,i,t],this)}afterTickToLabelConversion(){d(this.options.afterTickToLabelConversion,[this])}beforeCalculateLabelRotation(){d(this.options.beforeCalculateLabelRotation,[this])}calculateLabelRotation(){const t=this.options,e=t.ticks,i=qs(this.ticks.length,t.ticks.maxTicksLimit),s=e.minRotation||0,n=e.maxRotation;let o,a,r,l=s;if(!this._isVisible()||!e.display||s>=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=Z(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Js(t.grid)-e.padding-Zs(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=Y(Math.min(Math.asin(Z((h.highest.height+6)/o,-1,1)),Math.asin(Z(a/r,-1,1))-Math.asin(Z(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){d(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){d(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=Zs(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Js(n)+o):(t.height=this.maxHeight,t.width=Js(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=$(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:"inner"!==n&&(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){d(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e<i;e++)s(t[e].label)&&(t.splice(e,1),i--,e--);this.afterTickToLabelConversion()}_getLabelSizes(){let t=this._labelSizes;if(!t){const e=this.options.ticks.sampleSize;let i=this.ticks;e<i.length&&(i=Ks(i,e)),this._labelSizes=t=this._computeLabelSizes(i,i.length,this.options.ticks.maxTicksLimit)}return t}_computeLabelSizes(t,e,i){const{ctx:o,_longestTextCache:a}=this,r=[],l=[],h=Math.floor(e/qs(e,i));let c,d,f,g,p,m,x,b,_,y,v,M=0,w=0;for(c=0;c<e;c+=h){if(g=t[c].label,p=this._resolveTickFontOptions(c),o.font=m=p.string,x=a[m]=a[m]||{data:{},gc:[]},b=p.lineHeight,_=y=0,s(g)||n(g)){if(n(g))for(d=0,f=g.length;d<f;++d)v=g[d],s(v)||n(v)||(_=Ce(o,x.data,x.gc,_,v),y+=b)}else _=Ce(o,x.data,x.gc,_,g),y=b;r.push(_),l.push(y),M=Math.max(_,M),w=Math.max(y,w)}!function(t,e){u(t,(t=>{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n<s;++n)delete t.data[i[n]];i.splice(0,s)}}))}(a,e);const k=r.indexOf(M),S=l.indexOf(w),P=t=>({width:r[t]||0,height:l[t]||0});return{first:P(0),last:P(e-1),widest:P(k),highest:P(S),widths:r,heights:l}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return Q(this._alignToPixels?Ae(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&t<e.length){const i=e[t];return i.$context||(i.$context=function(t,e,i){return Ci(t,{tick:i,index:e,type:"tick"})}(this.getContext(),t,i))}return this.$context||(this.$context=Ci(this.chart.getContext(),{scale:this,type:"scale"}))}_tickSize(){const t=this.options.ticks,e=$(this.labelRotation),i=Math.abs(Math.cos(e)),s=Math.abs(Math.sin(e)),n=this._getLabelSizes(),o=t.autoSkipPadding||0,a=n?n.widest.width+o:0,r=n?n.highest.height+o:0;return this.isHorizontal()?r*i>a*s?a/i:r/s:r*s<a*i?r/i:a/s}_isVisible(){const t=this.options.display;return"auto"!==t?!!t:this.getMatchingVisibleMetas().length>0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:a,border:r}=s,h=n.offset,c=this.isHorizontal(),d=this.ticks.length+(h?1:0),u=Js(n),f=[],g=r.setContext(this.getContext()),p=g.display?g.width:0,m=p/2,x=function(t){return Ae(i,t,p)};let b,_,y,v,M,w,k,S,P,D,C,O;if("top"===a)b=x(this.bottom),w=this.bottom-u,S=b-m,D=x(t.top)+m,O=t.bottom;else if("bottom"===a)b=x(this.top),D=t.top,O=x(t.bottom)-m,w=b+m,S=this.top+u;else if("left"===a)b=x(this.right),M=this.right-u,k=b-m,P=x(t.left)+m,C=t.right;else if("right"===a)b=x(this.left),P=t.left,C=x(t.right)-m,M=b+m,k=this.left+u;else if("x"===e){if("center"===a)b=x((t.top+t.bottom)/2+.5);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}D=t.top,O=t.bottom,w=b+m,S=w+u}else if("y"===e){if("center"===a)b=x((t.left+t.right)/2);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}M=b-m,k=M-u,P=t.left,C=t.right}const A=l(s.ticks.maxTicksLimit,d),T=Math.max(1,Math.ceil(d/A));for(_=0;_<d;_+=T){const t=this.getContext(_),e=n.setContext(t),s=r.setContext(t),o=e.lineWidth,a=e.color,l=s.dash||[],d=s.dashOffset,u=e.tickWidth,g=e.tickColor,p=e.tickBorderDash||[],m=e.tickBorderDashOffset;y=Gs(this,_,h),void 0!==y&&(v=Ae(i,y,o),c?M=k=P=C=v:w=S=D=O=v,f.push({tx1:M,ty1:w,tx2:k,ty2:S,x1:P,y1:D,x2:C,y2:O,width:o,color:a,borderDash:l,borderDashOffset:d,tickWidth:u,tickColor:g,tickBorderDash:p,tickBorderDashOffset:m}))}return this._ticksLength=d,this._borderValue=b,f}_computeLabelItems(t){const e=this.axis,i=this.options,{position:s,ticks:a}=i,r=this.isHorizontal(),l=this.ticks,{align:h,crossAlign:c,padding:d,mirror:u}=a,f=Js(i.grid),g=f+d,p=u?-d:g,m=-$(this.labelRotation),x=[];let b,_,y,v,M,w,k,S,P,D,C,O,A="middle";if("top"===s)w=this.bottom-p,k=this._getXAxisLabelAlignment();else if("bottom"===s)w=this.top+p,k=this._getXAxisLabelAlignment();else if("left"===s){const t=this._getYAxisLabelAlignment(f);k=t.textAlign,M=t.x}else if("right"===s){const t=this._getYAxisLabelAlignment(f);k=t.textAlign,M=t.x}else if("x"===e){if("center"===s)w=(t.top+t.bottom)/2+g;else if(o(s)){const t=Object.keys(s)[0],e=s[t];w=this.chart.scales[t].getPixelForValue(e)+g}k=this._getXAxisLabelAlignment()}else if("y"===e){if("center"===s)M=(t.left+t.right)/2-g;else if(o(s)){const t=Object.keys(s)[0],e=s[t];M=this.chart.scales[t].getPixelForValue(e)}k=this._getYAxisLabelAlignment(f).textAlign}"y"===e&&("start"===h?A="top":"end"===h&&(A="bottom"));const T=this._getLabelSizes();for(b=0,_=l.length;b<_;++b){y=l[b],v=y.label;const t=a.setContext(this.getContext(b));S=this.getPixelForTick(b)+a.labelOffset,P=this._resolveTickFontOptions(b),D=P.lineHeight,C=n(v)?v.length:1;const e=C/2,i=t.color,o=t.textStrokeColor,h=t.textStrokeWidth;let d,f=k;if(r?(M=S,"inner"===k&&(f=b===_-1?this.options.reverse?"left":"right":0===b?this.options.reverse?"right":"left":"center"),O="top"===s?"near"===c||0!==m?-C*D+D/2:"center"===c?-T.highest.height/2-e*D+D:-T.highest.height+D/2:"near"===c||0!==m?D/2:"center"===c?T.highest.height/2-e*D:T.highest.height-C*D,u&&(O*=-1),0===m||t.showLabelBackdrop||(M+=D/2*Math.sin(m))):(w=S,O=(1-C)*D/2),t.showLabelBackdrop){const e=ki(t.backdropPadding),i=T.heights[b],s=T.widths[b];let n=O-e.top,o=0-e.left;switch(A){case"middle":n-=i/2;break;case"bottom":n-=i}switch(k){case"center":o-=s/2;break;case"right":o-=s;break;case"inner":b===_-1?o-=s:b>0&&(o-=s/2)}d={left:o,top:n,width:s+e.width,height:i+e.height,color:t.backdropColor}}x.push({label:v,font:P,textOffset:O,options:{rotation:m,color:i,strokeColor:o,strokeWidth:h,textAlign:f,textBaseline:A,translation:[M,w],backdrop:d}})}return x}_getXAxisLabelAlignment(){const{position:t,ticks:e}=this.options;if(-$(this.labelRotation))return"top"===t?"left":"right";let i="center";return"start"===e.align?i="left":"end"===e.align?i="right":"inner"===e.align&&(i="inner"),i}_getYAxisLabelAlignment(t){const{position:e,ticks:{crossAlign:i,mirror:s,padding:n}}=this.options,o=t+n,a=this._getLabelSizes().widest.width;let r,l;return"left"===e?s?(l=this.right+n,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l+=a)):(l=this.right-o,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l=this.left)):"right"===e?s?(l=this.left+n,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l-=a)):(l=this.left+o,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l=this.right)):r="right",{textAlign:r,x:l}}_computeLabelArea(){if(this.options.ticks.mirror)return;const t=this.chart,e=this.options.position;return"left"===e||"right"===e?{top:0,left:this.left,bottom:t.height,right:this.right}:"top"===e||"bottom"===e?{top:this.top,left:0,bottom:this.bottom,right:t.width}:void 0}drawBackground(){const{ctx:t,options:{backgroundColor:e},left:i,top:s,width:n,height:o}=this;e&&(t.save(),t.fillStyle=e,t.fillRect(i,s,n,o),t.restore())}getLineWidthForValue(t){const e=this.options.grid;if(!this._isVisible()||!e.display)return 0;const i=this.ticks.findIndex((e=>e.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n<o;++n){const t=s[n];e.drawOnChartArea&&a({x:t.x1,y:t.y1},{x:t.x2,y:t.y2},t),e.drawTicks&&a({x:t.tx1,y:t.ty1},{x:t.tx2,y:t.ty2},{color:t.tickColor,width:t.tickWidth,borderDash:t.tickBorderDash,borderDashOffset:t.tickBorderDashOffset})}}drawBorder(){const{chart:t,ctx:e,options:{border:i,grid:s}}=this,n=i.setContext(this.getContext()),o=i.display?n.width:0;if(!o)return;const a=s.setContext(this.getContext(0)).lineWidth,r=this._borderValue;let l,h,c,d;this.isHorizontal()?(l=Ae(t,this.left,o)-o/2,h=Ae(t,this.right,a)+a/2,c=d=r):(c=Ae(t,this.top,o)-o/2,d=Ae(t,this.bottom,a)+a/2,l=h=r),e.save(),e.lineWidth=n.width,e.strokeStyle=n.color,e.beginPath(),e.moveTo(l,c),e.lineTo(h,d),e.stroke(),e.restore()}drawLabels(t){if(!this.options.ticks.display)return;const e=this.ctx,i=this._computeLabelArea();i&&Ie(e,i);const s=this.getLabelItems(t);for(const t of s){const i=t.options,s=t.font;Ne(e,t.label,0,t.textOffset,s,i)}i&&ze(e)}drawTitle(){const{ctx:t,options:{position:e,title:i,reverse:s}}=this;if(!i.display)return;const a=Si(i.font),r=ki(i.padding),l=i.align;let h=a.lineHeight/2;"bottom"===e||"center"===e||o(e)?(h+=r.bottom,n(i.text)&&(h+=a.lineHeight*(i.text.length-1))):h+=r.top;const{titleX:c,titleY:d,maxWidth:u,rotation:f}=function(t,e,i,s){const{top:n,left:a,bottom:r,right:l,chart:h}=t,{chartArea:c,scales:d}=h;let u,f,g,p=0;const m=r-n,x=l-a;if(t.isHorizontal()){if(f=ft(s,a,l),o(i)){const t=Object.keys(i)[0],s=i[t];g=d[t].getPixelForValue(s)+m-e}else g="center"===i?(c.bottom+c.top)/2+m-e:Xs(t,i,e);u=l-a}else{if(o(i)){const t=Object.keys(i)[0],s=i[t];f=d[t].getPixelForValue(s)-x+e}else f="center"===i?(c.left+c.right)/2-x+e:Xs(t,i,e);g=ft(s,r,n),p="left"===i?-E:E}return{titleX:f,titleY:g,maxWidth:u,rotation:p}}(this,h,e,l);Ne(t,i.text,0,0,a,{color:i.color,maxWidth:u,rotation:f,textAlign:Qs(l,e,s),textBaseline:"middle",translation:[c,d]})}draw(t){this._isVisible()&&(this.drawBackground(),this.drawGrid(t),this.drawBorder(),this.drawTitle(),this.drawLabels(t))}_layers(){const t=this.options,e=t.ticks&&t.ticks.z||0,i=l(t.grid&&t.grid.z,-1),s=l(t.border&&t.border.z,0);return this._isVisible()&&this.draw===tn.prototype.draw?[{z:i,draw:t=>{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:s,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n<o;++n){const o=e[n];o[i]!==this.id||t&&o.type!==t||s.push(o)}return s}_resolveTickFontOptions(t){return Si(this.options.ticks.setContext(this.getContext(t)).font)}_maxDigits(){const t=this._resolveTickFontOptions(0).lineHeight;return(this.isHorizontal()?this.width:this.height)/t}}class en{constructor(t,e,i){this.type=t,this.scope=e,this.override=i,this.items=Object.create(null)}isForType(t){return Object.prototype.isPrototypeOf.call(this.type.prototype,t.prototype)}register(t){const e=Object.getPrototypeOf(t);let i;(function(t){return"id"in t&&"defaults"in t})(e)&&(i=this.register(e));const s=this.items,n=t.id,o=this.scope+"."+n;if(!n)throw new Error("class does not have id: "+t);return n in s||(s[n]=t,function(t,e,i){const s=x(Object.create(null),[i?ue.get(i):{},ue.get(e),t.defaults]);ue.set(e,s),t.defaultRoutes&&function(t,e){Object.keys(e).forEach((i=>{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");ue.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&ue.describe(e,t.descriptors)}(t,o,i),this.override&&ue.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in ue[s]&&(delete ue[s][i],this.override&&delete re[i])}}class sn{constructor(){this.controllers=new en(js,"datasets",!0),this.elements=new en($s,"elements"),this.plugins=new en(Object,"plugins"),this.scales=new en(tn,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):u(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=w(t);d(i["before"+s],[],i),e[t](i),d(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;e<this._typedRegistries.length;e++){const i=this._typedRegistries[e];if(i.isForType(t))return i}return this.plugins}_get(t,e,i){const s=e.get(t);if(void 0===s)throw new Error('"'+t+'" is not a registered '+i+".");return s}}var nn=new sn;class on{constructor(){this._init=[]}notify(t,e,i,s){"beforeInit"===e&&(this._init=this._createDescriptors(t,!0),this._notify(this._init,t,"install"));const n=s?this._descriptors(t).filter(s):this._descriptors(t),o=this._notify(n,t,e,i);return"afterDestroy"===e&&(this._notify(n,t,"stop"),this._notify(this._init,t,"uninstall")),o}_notify(t,e,i,s){s=s||{};for(const n of t){const t=n.plugin;if(!1===d(t[i],[e,s,n.options],t)&&s.cancelable)return!1}return!0}invalidate(){s(this._cache)||(this._oldCache=this._cache,this._cache=void 0)}_descriptors(t){if(this._cache)return this._cache;const e=this._cache=this._createDescriptors(t);return this._notifyStateChanges(t),e}_createDescriptors(t,e){const i=t&&t.config,s=l(i.options&&i.options.plugins,{}),n=function(t){const e={},i=[],s=Object.keys(nn.plugins.items);for(let t=0;t<s.length;t++)i.push(nn.getPlugin(s[t]));const n=t.plugins||[];for(let t=0;t<n.length;t++){const s=n[t];-1===i.indexOf(s)&&(i.push(s),e[s.id]=!0)}return{plugins:i,localIds:e}}(i);return!1!==s||e?function(t,{plugins:e,localIds:i},s,n){const o=[],a=t.getContext();for(const r of e){const e=r.id,l=an(s[e],n);null!==l&&o.push({plugin:r,options:rn(t.config,{plugin:r,local:i[e]},l,a)})}return o}(t,n,s,e):[]}_notifyStateChanges(t){const e=this._oldCache||[],i=this._cache,s=(t,e)=>t.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function an(t,e){return e||!1!==t?!0===t?{}:t:null}function rn(t,{plugin:e,local:i},s,n){const o=t.pluginScopeKeys(e),a=t.getOptionScopes(s,o);return i&&e.defaults&&a.push(e.defaults),t.createResolver(a,n,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function ln(t,e){const i=ue.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function hn(t){if("x"===t||"y"===t||"r"===t)return t}function cn(t,...e){if(hn(t))return t;for(const s of e){const e=s.axis||("top"===(i=s.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.length>1&&hn(t[0].toLowerCase());if(e)return e}var i;throw new Error(`Cannot determine type of '${t}' axis. Please provide 'axis' or 'position' option.`)}function dn(t,e,i){if(i[e+"AxisID"]===t)return{axis:e}}function un(t,e){const i=re[t.type]||{scales:{}},s=e.scales||{},n=ln(t.type,e),a=Object.create(null);return Object.keys(s).forEach((e=>{const r=s[e];if(!o(r))return console.error(`Invalid scale configuration for scale: ${e}`);if(r._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${e}`);const l=cn(e,r,function(t,e){if(e.data&&e.data.datasets){const i=e.data.datasets.filter((e=>e.xAxisID===t||e.yAxisID===t));if(i.length)return dn(t,"x",i[0])||dn(t,"y",i[0])}return{}}(e,t),ue.scales[r.type]),h=function(t,e){return t===e?"_index_":"_value_"}(l,n),c=i.scales||{};a[e]=b(Object.create(null),[{axis:l},r,c[l],c[h]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,o=i.indexAxis||ln(n,e),r=(re[n]||{}).scales||{};Object.keys(r).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,o),n=i[e+"AxisID"]||e;a[n]=a[n]||Object.create(null),b(a[n],[{axis:e},s[n],r[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];b(e,[ue.scales[e.type],ue.scale])})),a}function fn(t){const e=t.options||(t.options={});e.plugins=l(e.plugins,{}),e.scales=un(t,e)}function gn(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const pn=new Map,mn=new Set;function xn(t,e){let i=pn.get(t);return i||(i=e(),pn.set(t,i),mn.add(i)),i}const bn=(t,e,i)=>{const s=M(e,i);void 0!==s&&t.add(s)};class _n{constructor(t){this._config=function(t){return(t=t||{}).data=gn(t.data),fn(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=gn(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),fn(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return xn(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return xn(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return xn(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return xn(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>bn(r,t,e)))),e.forEach((t=>bn(r,s,t))),e.forEach((t=>bn(r,re[n]||{},t))),e.forEach((t=>bn(r,ue,t))),e.forEach((t=>bn(r,le,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),mn.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,re[e]||{},ue.datasets[e]||{},{type:e},ue,le]}resolveNamedOptions(t,e,i,s=[""]){const o={$shared:!0},{resolver:a,subPrefixes:r}=yn(this._resolverCache,t,s);let l=a;if(function(t,e){const{isScriptable:i,isIndexable:s}=Ye(t);for(const o of e){const e=i(o),a=s(o),r=(a||e)&&t[o];if(e&&(S(r)||vn(r))||a&&n(r))return!0}return!1}(a,e)){o.$shared=!1;l=$e(a,i=S(i)?i():i,this.createResolver(t,i,r))}for(const t of e)o[t]=l[t];return o}createResolver(t,e,i=[""],s){const{resolver:n}=yn(this._resolverCache,t,i);return o(e)?$e(n,e,void 0,s):n}}function yn(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:je(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const vn=t=>o(t)&&Object.getOwnPropertyNames(t).some((e=>S(t[e])));const Mn=["top","bottom","left","right","chartArea"];function wn(t,e){return"top"===t||"bottom"===t||-1===Mn.indexOf(t)&&"x"===e}function kn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function Sn(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),d(i&&i.onComplete,[t],e)}function Pn(t){const e=t.chart,i=e.options.animation;d(i&&i.onProgress,[t],e)}function Dn(t){return fe()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const Cn={},On=t=>{const e=Dn(t);return Object.values(Cn).filter((t=>t.canvas===e)).pop()};function An(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}class Tn{static defaults=ue;static instances=Cn;static overrides=re;static registry=nn;static version="4.5.0";static getChart=On;static register(...t){nn.add(...t),Ln()}static unregister(...t){nn.remove(...t),Ln()}constructor(t,e){const s=this.config=new _n(e),n=Dn(t),o=On(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas with ID '"+o.canvas.id+"' can be reused.");const a=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||Ps(n)),this.platform.updateConfig(s);const r=this.platform.acquireContext(n,a.aspectRatio),l=r&&r.canvas,h=l&&l.height,c=l&&l.width;this.id=i(),this.ctx=r,this.canvas=l,this.width=c,this.height=h,this._options=a,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new on,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=dt((t=>this.update(t)),a.resizeDelay||0),this._dataChanges=[],Cn[this.id]=this,r&&l?(bt.listen(this,"complete",Sn),bt.listen(this,"progress",Pn),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:n,_aspectRatio:o}=this;return s(t)?e&&o?o:n?i/n:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return nn}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Te(this.canvas,this.ctx),this}stop(){return bt.stop(this),this}resize(t,e){bt.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),d(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){u(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=cn(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),u(n,(e=>{const n=e.options,o=n.id,a=cn(o,n),r=l(n.type,e.dtype);void 0!==n.position&&wn(n.position,a)===wn(e.dposition)||(n.position=e.dposition),s[o]=!0;let h=null;if(o in i&&i[o].type===r)h=i[o];else{h=new(nn.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[h.id]=h}h.init(n,t)})),u(s,((t,e)=>{t||delete i[e]})),u(i,(t=>{ls.configure(this,t,t.options),ls.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;t<i;++t)this._destroyDatasetMeta(t);t.splice(e,i-e)}this._sortedMetasets=t.slice(0).sort(kn("order","index"))}_removeUnreferencedMetasets(){const{_metasets:t,data:{datasets:e}}=this;t.length>e.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i<s;i++){const s=e[i];let n=this.getDatasetMeta(i);const o=s.type||this.config.type;if(n.type&&n.type!==o&&(this._destroyDatasetMeta(i),n=this.getDatasetMeta(i)),n.type=o,n.indexAxis=s.indexAxis||ln(o,this.options),n.order=s.order||0,n.index=i,n.label=""+s.label,n.visible=this.isDatasetVisible(i),n.controller)n.controller.updateIndex(i),n.controller.linkScales();else{const e=nn.getController(o),{datasetElementType:s,dataElementType:a}=ue.datasets[o];Object.assign(e,{dataElementType:nn.getElement(a),datasetElementType:s&&nn.getElement(s)}),n.controller=new e(this,i),t.push(n.controller)}}return this._updateMetasets(),t}_resetElements(){u(this.data.datasets,((t,e)=>{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t<e;t++){const{controller:e}=this.getDatasetMeta(t),i=!s&&-1===n.indexOf(e);e.buildOrUpdateElements(i),o=Math.max(+e.getMaxOverflow(),o)}o=this._minPadding=i.layout.autoPadding?o:0,this._updateLayout(o),s||u(n,(t=>{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(kn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){u(this.scales,(t=>{ls.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);P(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){An(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;t<e;t++)if(!P(s,i(t)))return;return Array.from(s).map((t=>t.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ls.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],u(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t<e;++t)this.getDatasetMeta(t).controller.configure();for(let e=0,i=this.data.datasets.length;e<i;++e)this._updateDataset(e,S(t)?t({datasetIndex:e}):t);this.notifyPlugins("afterDatasetsUpdate",{mode:t})}}_updateDataset(t,e){const i=this.getDatasetMeta(t),s={meta:i,index:t,mode:e,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetUpdate",s)&&(i.controller._update(e),s.cancelable=!1,this.notifyPlugins("afterDatasetUpdate",s))}render(){!1!==this.notifyPlugins("beforeRender",{cancelable:!0})&&(bt.has(this)?this.attached&&!bt.running(this)&&bt.start(this):(this.draw(),Sn({chart:this})))}draw(){let t;if(this._resizeBeforeDraw){const{width:t,height:e}=this._resizeBeforeDraw;this._resizeBeforeDraw=null,this._resize(t,e)}if(this.clear(),this.width<=0||this.height<=0)return;if(!1===this.notifyPlugins("beforeDraw",{cancelable:!0}))return;const e=this._layers;for(t=0;t<e.length&&e[t].z<=0;++t)e[t].draw(this.chartArea);for(this._drawDatasets();t<e.length;++t)e[t].draw(this.chartArea);this.notifyPlugins("afterDraw")}_getSortedDatasetMetas(t){const e=this._sortedMetasets,i=[];let s,n;for(s=0,n=e.length;s<n;++s){const n=e[s];t&&!n.visible||i.push(n)}return i}getSortedVisibleDatasetMetas(){return this._getSortedDatasetMetas(!0)}_drawDatasets(){if(!1===this.notifyPlugins("beforeDatasetsDraw",{cancelable:!0}))return;const t=this.getSortedVisibleDatasetMetas();for(let e=t.length-1;e>=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i={meta:t,index:t.index,cancelable:!0},s=Ni(this,t);!1!==this.notifyPlugins("beforeDatasetDraw",i)&&(s&&Ie(e,s),t.controller.draw(),s&&ze(e),i.cancelable=!1,this.notifyPlugins("afterDatasetDraw",i))}isPointInArea(t){return Re(t,this.chartArea,this._minPadding)}getElementsAtEventForMode(t,e,i,s){const n=Ki.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ci(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);k(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),bt.remove(this),t=0,e=this.data.datasets.length;t<e;++t)this._destroyDatasetMeta(t)}destroy(){this.notifyPlugins("beforeDestroy");const{canvas:t,ctx:e}=this;this._stop(),this.config.clearCache(),t&&(this.unbindEvents(),Te(t,e),this.platform.releaseContext(e),this.canvas=null,this.ctx=null),delete Cn[this.id],this.notifyPlugins("afterDestroy")}toBase64Image(...t){return this.canvas.toDataURL(...t)}bindEvents(){this.bindUserEvents(),this.options.responsive?this.bindResponsiveEvents():this.attached=!0}bindUserEvents(){const t=this._listeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};u(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){u(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},u(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a<r;++a){o=t[a];const e=o&&this.getDatasetMeta(o.datasetIndex).controller;e&&e[s+"HoverStyle"](o.element,o.datasetIndex,o.index)}}getActiveElements(){return this._active||[]}setActiveElements(t){const e=this._active||[],i=t.map((({datasetIndex:t,index:e})=>{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!f(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}isPluginEnabled(t){return 1===this._plugins._cache.filter((e=>e.plugin.id===t)).length}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:this.isPointInArea(t)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=D(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,d(n.onHover,[t,a,this],this),r&&d(n.onClick,[t,a,this],this));const h=!f(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}function Ln(){return u(Tn.instances,(t=>t._plugins.invalidate()))}function En(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class Rn{static override(t){Object.assign(Rn.prototype,t)}options;constructor(t){this.options=t||{}}init(){}formats(){return En()}parse(){return En()}format(){return En()}add(){return En()}diff(){return En()}startOf(){return En()}endOf(){return En()}}var In={_date:Rn};function zn(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;e<n;e++)s=s.concat(i[e].controller.getAllParsedValues(t));t._cache.$bar=lt(s.sort(((t,e)=>t-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(k(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;s<n;++s)o=e.getPixelForValue(i[s]),l();for(a=void 0,s=0,n=e.ticks.length;s<n;++s)o=e.getPixelForTick(s),l();return r}function Fn(t,e,i,s){return n(t)?function(t,e,i,s){const n=i.parse(t[0],s),o=i.parse(t[1],s),a=Math.min(n,o),r=Math.max(n,o);let l=a,h=r;Math.abs(a)>Math.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function Vn(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;h<c;++h)u=e[h],d={},d[n.axis]=r||n.parse(a[h],h),l.push(Fn(u,d,o,h));return l}function Bn(t){return t&&void 0!==t.barStart&&void 0!==t.barEnd}function Wn(t,e,i,s){let n=e.borderSkipped;const o={};if(!n)return void(t.borderSkipped=o);if(!0===n)return void(t.borderSkipped={top:!0,right:!0,bottom:!0,left:!0});const{start:a,end:r,reverse:l,top:h,bottom:c}=function(t){let e,i,s,n,o;return t.horizontal?(e=t.base>t.x,i="left",s="right"):(e=t.base<t.y,i="bottom",s="top"),e?(n="end",o="start"):(n="start",o="end"),{start:i,end:s,reverse:e,top:n,bottom:o}}(t);"middle"===n&&i&&(t.enableBorderRadius=!0,(i._top||0)===s?n=h:(i._bottom||0)===s?n=c:(o[Nn(c,a,r,l)]=!0,n=h)),o[Nn(n,a,r,l)]=!0,t.borderSkipped=o}function Nn(t,e,i,s){var n,o,a;return s?(a=i,t=Hn(t=(n=t)===(o=e)?a:n===a?o:n,i,e)):t=Hn(t,e,i),t}function Hn(t,e,i){return"start"===t?e:"end"===t?i:t}function jn(t,{inflateAmount:e},i){t.inflateAmount="auto"===e?1===i?.33:0:e}class $n extends js{static id="doughnut";static defaults={datasetElementType:!1,dataElementType:"arc",animation:{animateRotate:!0,animateScale:!1},animations:{numbers:{type:"number",properties:["circumference","endAngle","innerRadius","outerRadius","startAngle","x","y","offset","borderWidth","spacing"]}},cutout:"50%",rotation:0,circumference:360,radius:"100%",spacing:0,indexAxis:"r"};static descriptors={_scriptable:t=>"spacing"!==t,_indexable:t=>"spacing"!==t&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i,color:s}}=t.legend.options;return e.labels.map(((e,n)=>{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}}};constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,a,r=t=>+i[t];if(o(i[t])){const{key:t="value"}=this._parsing;r=e=>+M(i[e],t)}for(n=t,a=t+e;n<a;++n)s._parsed[n]=r(n)}}_getRotation(){return $(this.options.rotation-90)}_getCircumference(){return $(this.options.circumference)}_getRotationExtents(){let t=O,e=-O;for(let i=0;i<this.chart.data.datasets.length;++i)if(this.chart.isDatasetVisible(i)&&this.chart.getDatasetMeta(i).type===this._type){const s=this.chart.getDatasetMeta(i).controller,n=s._getRotation(),o=s._getCircumference();t=Math.min(t,n),e=Math.max(e,n+o)}return{rotation:t,circumference:e-t}}update(t){const e=this.chart,{chartArea:i}=e,s=this._cachedMeta,n=s.data,o=this.getMaxBorderWidth()+this.getMaxOffset(n)+this.options.spacing,a=Math.max((Math.min(i.width,i.height)-o)/2,0),r=Math.min(h(this.options.cutout,a),1),l=this._getRingWeight(this.index),{circumference:d,rotation:u}=this._getRotationExtents(),{ratioX:f,ratioY:g,offsetX:p,offsetY:m}=function(t,e,i){let s=1,n=1,o=0,a=0;if(e<O){const r=t,l=r+e,h=Math.cos(r),c=Math.sin(r),d=Math.cos(l),u=Math.sin(l),f=(t,e,s)=>J(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>J(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(E,c,u),x=g(C,h,d),b=g(C+E,c,u);s=(p-x)/2,n=(m-b)/2,o=-(p+x)/2,a=-(m+b)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(u,d,r),x=(i.width-o)/f,b=(i.height-o)/g,_=Math.max(Math.min(x,b)/2,0),y=c(this.options.radius,_),v=(y-Math.max(y*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=p*y,this.offsetY=m*y,s.total=this.calculateTotal(),this.outerRadius=y-v*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-v*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/O)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,{sharedOptions:f,includeOptions:g}=this._getSharedOptions(e,s);let p,m=this._getRotation();for(p=0;p<e;++p)m+=this._circumference(p,n);for(p=e;p<e+i;++p){const e=this._circumference(p,n),i=t[p],o={x:l+this.offsetX,y:h+this.offsetY,startAngle:m,endAngle:m+e,circumference:e,outerRadius:u,innerRadius:d};g&&(o.options=f||this.resolveDataElementOptions(p,i.active?"active":s)),m+=e,this.updateElement(i,p,o,s)}}calculateTotal(){const t=this._cachedMeta,e=t.data;let i,s=0;for(i=0;i<e.length;i++){const n=t._parsed[i];null===n||isNaN(n)||!this.chart.getDataVisibility(i)||e[i].hidden||(s+=Math.abs(n))}return s}calculateCircumference(t){const e=this._cachedMeta.total;return e>0&&!isNaN(t)?O*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s<n;++s)if(i.isDatasetVisible(s)){o=i.getDatasetMeta(s),t=o.data,a=o.controller;break}if(!t)return 0;for(s=0,n=t.length;s<n;++s)r=a.resolveDataElementOptions(s),"inner"!==r.borderAlign&&(e=Math.max(e,r.borderWidth||0,r.hoverBorderWidth||0));return e}getMaxOffset(t){let e=0;for(let i=0,s=t.length;i<s;++i){const t=this.resolveDataElementOptions(i);e=Math.max(e,t.offset||0,t.hoverOffset||0)}return e}_getRingWeightOffset(t){let e=0;for(let i=0;i<t;++i)this.chart.isDatasetVisible(i)&&(e+=this._getRingWeight(i));return e}_getRingWeight(t){return Math.max(l(this.chart.data.datasets[t].weight,1),0)}_getVisibleDatasetWeightTotal(){return this._getRingWeightOffset(this.chart.data.datasets.length)||1}}class Yn extends js{static id="polarArea";static defaults={dataElementType:"arc",animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:"number",properties:["x","y","startAngle","endAngle","innerRadius","outerRadius"]}},indexAxis:"r",startAngle:0};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i,color:s}}=t.legend.options;return e.labels.map(((e,n)=>{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}getMinMax(){const t=this._cachedMeta,e={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach(((t,i)=>{const s=this.getParsed(i).r;!isNaN(s)&&this.chart.getDataVisibility(i)&&(s<e.min&&(e.min=s),s>e.max&&(e.max=s))})),e}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.options.animation,r=this._cachedMeta.rScale,l=r.xCenter,h=r.yCenter,c=r.getIndexAngle(0)-.5*C;let d,u=c;const f=360/this.countVisibleElements();for(d=0;d<e;++d)u+=this._computeAngle(d,s,f);for(d=e;d<e+i;d++){const e=t[d];let i=u,g=u+this._computeAngle(d,s,f),p=o.getDataVisibility(d)?r.getDistanceFromCenterForValue(this.getParsed(d).r):0;u=g,n&&(a.animateScale&&(p=0),a.animateRotate&&(i=g=c));const m={x:l,y:h,innerRadius:0,outerRadius:p,startAngle:i,endAngle:g,options:this.resolveDataElementOptions(d,e.active?"active":s)};this.updateElement(e,d,m,s)}}countVisibleElements(){const t=this._cachedMeta;let e=0;return t.data.forEach(((t,i)=>{!isNaN(this.getParsed(i).r)&&this.chart.getDataVisibility(i)&&e++})),e}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?$(this.resolveDataElementOptions(t,e).angle||i):0}}var Un=Object.freeze({__proto__:null,BarController:class extends js{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(t,e,i,s){return Vn(t,e,i,s)}parseArrayData(t,e,i,s){return Vn(t,e,i,s)}parseObjectData(t,e,i,s){const{iScale:n,vScale:o}=t,{xAxisKey:a="x",yAxisKey:r="y"}=this._parsing,l="x"===n.axis?a:r,h="x"===o.axis?a:r,c=[];let d,u,f,g;for(d=i,u=i+s;d<u;++d)g=e[d],f={},f[n.axis]=n.parse(M(g,l),d),c.push(Fn(M(g,h),f,o,d));return c}updateRangeFromParsed(t,e,i,s){super.updateRangeFromParsed(t,e,i,s);const n=i._custom;n&&e===this._cachedMeta.vScale&&(t.min=Math.min(t.min,n.min),t.max=Math.max(t.max,n.max))}getMaxOverflow(){return 0}getLabelAndValue(t){const e=this._cachedMeta,{iScale:i,vScale:s}=e,n=this.getParsed(t),o=n._custom,a=Bn(o)?"["+o.start+", "+o.end+"]":""+s.getLabelForValue(n[s.axis]);return{label:""+i.getLabelForValue(n[i.axis]),value:a}}initialize(){this.enableOptionSharing=!0,super.initialize();this._cachedMeta.stack=this.getDataset().stack}update(t){const e=this._cachedMeta;this.updateElements(e.data,0,e.data.length,t)}updateElements(t,e,i,n){const o="reset"===n,{index:a,_cachedMeta:{vScale:r}}=this,l=r.getBasePixel(),h=r.isHorizontal(),c=this._getRuler(),{sharedOptions:d,includeOptions:u}=this._getSharedOptions(e,n);for(let f=e;f<e+i;f++){const e=this.getParsed(f),i=o||s(e[r.axis])?{base:l,head:l}:this._calculateBarValuePixels(f),g=this._calculateBarIndexPixels(f,c),p=(e._stacks||{})[r.axis],m={horizontal:h,base:i.base,enableBorderRadius:!p||Bn(e._custom)||a===p._top||a===p._bottom,x:h?i.head:g.center,y:h?g.center:i.head,height:h?g.size:Math.abs(i.size),width:h?Math.abs(i.size):g.size};u&&(m.options=d||this.resolveDataElementOptions(f,t[f].active?"active":n));const x=m.options||t[f].options;Wn(m,x,p,a),jn(m,x,c.ratio),this.updateElement(t[f],f,m,n)}}_getStacks(t,e){const{iScale:i}=this._cachedMeta,n=i.getMatchingVisibleMetas(this._type).filter((t=>t.controller.options.grouped)),o=i.options.stacked,a=[],r=this._cachedMeta.controller.getParsed(e),l=r&&r[i.axis],h=t=>{const e=t._parsed.find((t=>t[i.axis]===l)),n=e&&e[t.vScale.axis];if(s(n)||isNaN(n))return!0};for(const i of n)if((void 0===e||!h(i))&&((!1===o||-1===a.indexOf(i.stack)||void 0===o&&void 0===i.stack)&&a.push(i.stack),i.index===t))break;return a.length||a.push(void 0),a}_getStackCount(t){return this._getStacks(void 0,t).length}_getAxisCount(){return this._getAxis().length}getFirstScaleIdForIndexAxis(){const t=this.chart.scales,e=this.chart.options.indexAxis;return Object.keys(t).filter((i=>t[i].axis===e)).shift()}_getAxis(){const t={},e=this.getFirstScaleIdForIndexAxis();for(const i of this.chart.data.datasets)t[l("x"===this.chart.options.indexAxis?i.xAxisID:i.yAxisID,e)]=!0;return Object.keys(t)}_getStackIndex(t,e,i){const s=this._getStacks(t,i),n=void 0!==e?s.indexOf(e):-1;return-1===n?s.length-1:n}_getRuler(){const t=this.options,e=this._cachedMeta,i=e.iScale,s=[];let n,o;for(n=0,o=e.data.length;n<o;++n)s.push(i.getPixelForValue(this.getParsed(n)[i.axis],n));const a=t.barThickness;return{min:a||zn(e),pixels:s,start:i._startPixel,end:i._endPixel,stackCount:this._getStackCount(),scale:i,grouped:t.grouped,ratio:a?1:t.categoryPercentage*t.barPercentage}}_calculateBarValuePixels(t){const{_cachedMeta:{vScale:e,_stacked:i,index:n},options:{base:o,minBarLength:a}}=this,r=o||0,l=this.getParsed(t),h=l._custom,c=Bn(h);let d,u,f=l[e.axis],g=0,p=i?this.applyStack(e,l,i):f;p!==f&&(g=p-f,p=f),c&&(f=h.barStart,p=h.barEnd-h.barStart,0!==f&&F(f)!==F(h.barEnd)&&(g=0),g+=f);const m=s(o)||c?g:o;let x=e.getPixelForValue(m);if(d=this.chart.getDataVisibility(t)?e.getPixelForValue(g+p):x,u=d-x,Math.abs(u)<a){u=function(t,e,i){return 0!==t?F(t):(e.isHorizontal()?1:-1)*(e.min>=i?1:-1)}(u,e,r)*a,f===r&&(x-=u/2);const t=e.getPixelForDecimal(0),s=e.getPixelForDecimal(1),o=Math.min(t,s),h=Math.max(t,s);x=Math.max(Math.min(x,h),o),d=x+u,i&&!c&&(l._stacks[e.axis]._visualValues[n]=e.getValueForPixel(d)-e.getValueForPixel(x))}if(x===e.getPixelForValue(r)){const t=F(u)*e.getLineWidthForValue(r)/2;x+=t,u-=t}return{size:u,base:x,head:d,center:d+u/2}}_calculateBarIndexPixels(t,e){const i=e.scale,n=this.options,o=n.skipNull,a=l(n.maxBarThickness,1/0);let r,h;const c=this._getAxisCount();if(e.grouped){const i=o?this._getStackCount(t):e.stackCount,d="flex"===n.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t<n.length-1?n[t+1]:null;const l=i.categoryPercentage;null===a&&(a=o-(null===r?e.end-e.start:r-o)),null===r&&(r=o+o-a);const h=o-(o-Math.min(a,r))/2*l;return{chunk:Math.abs(r-a)/2*l/s,ratio:i.barPercentage,start:h}}(t,e,n,i*c):function(t,e,i,n){const o=i.barThickness;let a,r;return s(o)?(a=e.min*i.categoryPercentage,r=i.barPercentage):(a=o*n,r=1),{chunk:a/n,ratio:r,start:e.pixels[t]-a/2}}(t,e,n,i*c),u="x"===this.chart.options.indexAxis?this.getDataset().xAxisID:this.getDataset().yAxisID,f=this._getAxis().indexOf(l(u,this.getFirstScaleIdForIndexAxis())),g=this._getStackIndex(this.index,this._cachedMeta.stack,o?t:void 0)+f;r=d.start+d.chunk*g+d.chunk/2,h=Math.min(a,d.chunk*d.ratio)}else r=i.getPixelForValue(this.getParsed(t)[i.axis],t),h=Math.min(a,e.min*e.ratio);return{base:r-h/2,head:r+h/2,center:r,size:h}}draw(){const t=this._cachedMeta,e=t.vScale,i=t.data,s=i.length;let n=0;for(;n<s;++n)null===this.getParsed(n)[e.axis]||i[n].hidden||i[n].draw(this._ctx)}},BubbleController:class extends js{static id="bubble";static defaults={datasetElementType:!1,dataElementType:"point",animations:{numbers:{type:"number",properties:["x","y","borderWidth","radius"]}}};static overrides={scales:{x:{type:"linear"},y:{type:"linear"}}};initialize(){this.enableOptionSharing=!0,super.initialize()}parsePrimitiveData(t,e,i,s){const n=super.parsePrimitiveData(t,e,i,s);for(let t=0;t<n.length;t++)n[t]._custom=this.resolveDataElementOptions(t+i).radius;return n}parseArrayData(t,e,i,s){const n=super.parseArrayData(t,e,i,s);for(let t=0;t<n.length;t++){const s=e[i+t];n[t]._custom=l(s[2],this.resolveDataElementOptions(t+i).radius)}return n}parseObjectData(t,e,i,s){const n=super.parseObjectData(t,e,i,s);for(let t=0;t<n.length;t++){const s=e[i+t];n[t]._custom=l(s&&s.r&&+s.r,this.resolveDataElementOptions(t+i).radius)}return n}getMaxOverflow(){const t=this._cachedMeta.data;let e=0;for(let i=t.length-1;i>=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart.data.labels||[],{xScale:s,yScale:n}=e,o=this.getParsed(t),a=s.getLabelForValue(o.x),r=n.getLabelForValue(o.y),l=o._custom;return{label:i[t]||"",value:"("+a+", "+r+(l?", "+l:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,{sharedOptions:r,includeOptions:l}=this._getSharedOptions(e,s),h=o.axis,c=a.axis;for(let d=e;d<e+i;d++){const e=t[d],i=!n&&this.getParsed(d),u={},f=u[h]=n?o.getPixelForDecimal(.5):o.getPixelForValue(i[h]),g=u[c]=n?a.getBasePixel():a.getPixelForValue(i[c]);u.skip=isNaN(f)||isNaN(g),l&&(u.options=r||this.resolveDataElementOptions(d,e.active?"active":s),n&&(u.options.radius=0)),this.updateElement(e,d,u,s)}}resolveDataElementOptions(t,e){const i=this.getParsed(t);let s=super.resolveDataElementOptions(t,e);s.$shared&&(s=Object.assign({},s,{$shared:!1}));const n=s.radius;return"active"!==e&&(s.radius=0),s.radius+=l(i&&i._custom,n),s}},DoughnutController:$n,LineController:class extends js{static id="line";static defaults={datasetElementType:"line",dataElementType:"point",showLine:!0,spanGaps:!1};static overrides={scales:{_index_:{type:"category"},_value_:{type:"linear"}}};initialize(){this.enableOptionSharing=!0,this.supportsDecimation=!0,super.initialize()}update(t){const e=this._cachedMeta,{dataset:i,data:s=[],_dataset:n}=e,o=this.chart._animationsDisabled;let{start:a,count:r}=pt(e,s,o);this._drawStart=a,this._drawCount=r,mt(e)&&(a=0,r=s.length),i._chart=this.chart,i._datasetIndex=this.index,i._decimated=!!n._decimated,i.points=s;const l=this.resolveDatasetElementOptions(t);this.options.showLine||(l.borderWidth=0),l.segment=this.options.segment,this.updateElement(i,void 0,{animated:!o,options:l},t),this.updateElements(s,a,r,t)}updateElements(t,e,i,n){const o="reset"===n,{iScale:a,vScale:r,_stacked:l,_dataset:h}=this._cachedMeta,{sharedOptions:c,includeOptions:d}=this._getSharedOptions(e,n),u=a.axis,f=r.axis,{spanGaps:g,segment:p}=this.options,m=N(g)?g:Number.POSITIVE_INFINITY,x=this.chart._animationsDisabled||o||"none"===n,b=e+i,_=t.length;let y=e>0&&this.getParsed(e-1);for(let i=0;i<_;++i){const g=t[i],_=x?g:{};if(i<e||i>=b){_.skip=!0;continue}const v=this.getParsed(i),M=s(v[f]),w=_[u]=a.getPixelForValue(v[u],i),k=_[f]=o||M?r.getBasePixel():r.getPixelForValue(l?this.applyStack(r,v,l):v[f],i);_.skip=isNaN(w)||isNaN(k)||M,_.stop=i>0&&Math.abs(v[u]-y[u])>m,p&&(_.parsed=v,_.raw=h.data[i]),d&&(_.options=c||this.resolveDataElementOptions(i,g.active?"active":n)),x||this.updateElement(g,i,_,n),y=v}}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}},PieController:class extends $n{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:Yn,RadarController:class extends js{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this._cachedMeta.rScale,o="reset"===s;for(let a=e;a<e+i;a++){const e=t[a],i=this.resolveDataElementOptions(a,e.active?"active":s),r=n.getPointPositionForValue(a,this.getParsed(a).r),l=o?n.xCenter:r.x,h=o?n.yCenter:r.y,c={x:l,y:h,angle:r.angle,skip:isNaN(l)||isNaN(h),options:i};this.updateElement(e,a,c,s)}}},ScatterController:class extends js{static id="scatter";static defaults={datasetElementType:!1,dataElementType:"point",showLine:!1,fill:!1};static overrides={interaction:{mode:"point"},scales:{x:{type:"linear"},y:{type:"linear"}}};getLabelAndValue(t){const e=this._cachedMeta,i=this.chart.data.labels||[],{xScale:s,yScale:n}=e,o=this.getParsed(t),a=s.getLabelForValue(o.x),r=n.getLabelForValue(o.y);return{label:i[t]||"",value:"("+a+", "+r+")"}}update(t){const e=this._cachedMeta,{data:i=[]}=e,s=this.chart._animationsDisabled;let{start:n,count:o}=pt(e,i,s);if(this._drawStart=n,this._drawCount=o,mt(e)&&(n=0,o=i.length),this.options.showLine){this.datasetElementType||this.addElements();const{dataset:n,_dataset:o}=e;n._chart=this.chart,n._datasetIndex=this.index,n._decimated=!!o._decimated,n.points=i;const a=this.resolveDatasetElementOptions(t);a.segment=this.options.segment,this.updateElement(n,void 0,{animated:!s,options:a},t)}else this.datasetElementType&&(delete e.dataset,this.datasetElementType=!1);this.updateElements(i,n,o,t)}addElements(){const{showLine:t}=this.options;!this.datasetElementType&&t&&(this.datasetElementType=this.chart.registry.getElement("line")),super.addElements()}updateElements(t,e,i,n){const o="reset"===n,{iScale:a,vScale:r,_stacked:l,_dataset:h}=this._cachedMeta,c=this.resolveDataElementOptions(e,n),d=this.getSharedOptions(c),u=this.includeOptions(n,d),f=a.axis,g=r.axis,{spanGaps:p,segment:m}=this.options,x=N(p)?p:Number.POSITIVE_INFINITY,b=this.chart._animationsDisabled||o||"none"===n;let _=e>0&&this.getParsed(e-1);for(let c=e;c<e+i;++c){const e=t[c],i=this.getParsed(c),p=b?e:{},y=s(i[g]),v=p[f]=a.getPixelForValue(i[f],c),M=p[g]=o||y?r.getBasePixel():r.getPixelForValue(l?this.applyStack(r,i,l):i[g],c);p.skip=isNaN(v)||isNaN(M)||y,p.stop=c>0&&Math.abs(i[f]-_[f])>x,m&&(p.parsed=i,p.raw=h.data[c]),u&&(p.options=d||this.resolveDataElementOptions(c,e.active?"active":n)),b||this.updateElement(e,c,p,n),_=i}this.updateSharedOptions(d,n,c)}getMaxOverflow(){const t=this._cachedMeta,e=t.data||[];if(!this.options.showLine){let t=0;for(let i=e.length-1;i>=0;--i)t=Math.max(t,e[i].size(this.resolveDataElementOptions(i))/2);return t>0&&t}const i=t.dataset,s=i.options&&i.options.borderWidth||0;if(!e.length)return s;const n=e[0].size(this.resolveDataElementOptions(0)),o=e[e.length-1].size(this.resolveDataElementOptions(e.length-1));return Math.max(s,n,o)/2}}});function Xn(t,e,i,s){const n=vi(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return Z(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:Z(n.innerStart,0,a),innerEnd:Z(n.innerEnd,0,a)}}function qn(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function Kn(t,e,i,s,n,o){const{x:a,y:r,startAngle:l,pixelMargin:h,innerRadius:c}=e,d=Math.max(e.outerRadius+s+i-h,0),u=c>0?c+s+i+h:0;let f=0;const g=n-l;if(s){const t=((c>0?c-s:0)+(d>0?d-s:0))/2;f=(g-(0!==t?g*t/(t+s):g))/2}const p=(g-Math.max(.001,g*d-i/C)/d)/2,m=l+p+f,x=n-p-f,{outerStart:b,outerEnd:_,innerStart:y,innerEnd:v}=Xn(e,u,d,x-m),M=d-b,w=d-_,k=m+b/M,S=x-_/w,P=u+y,D=u+v,O=m+y/P,A=x-v/D;if(t.beginPath(),o){const e=(k+S)/2;if(t.arc(a,r,d,k,e),t.arc(a,r,d,e,S),_>0){const e=qn(w,S,a,r);t.arc(e.x,e.y,_,S,x+E)}const i=qn(D,x,a,r);if(t.lineTo(i.x,i.y),v>0){const e=qn(D,A,a,r);t.arc(e.x,e.y,v,x+E,A+Math.PI)}const s=(x-v/u+(m+y/u))/2;if(t.arc(a,r,u,x-v/u,s,!0),t.arc(a,r,u,s,m+y/u,!0),y>0){const e=qn(P,O,a,r);t.arc(e.x,e.y,y,O+Math.PI,m-E)}const n=qn(M,m,a,r);if(t.lineTo(n.x,n.y),b>0){const e=qn(M,k,a,r);t.arc(e.x,e.y,b,m-E,k)}}else{t.moveTo(a,r);const e=Math.cos(k)*d+a,i=Math.sin(k)*d+r;t.lineTo(e,i);const s=Math.cos(S)*d+a,n=Math.sin(S)*d+r;t.lineTo(s,n)}t.closePath()}function Gn(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r,options:l}=e,{borderWidth:h,borderJoinStyle:c,borderDash:d,borderDashOffset:u,borderRadius:f}=l,g="inner"===l.borderAlign;if(!h)return;t.setLineDash(d||[]),t.lineDashOffset=u,g?(t.lineWidth=2*h,t.lineJoin=c||"round"):(t.lineWidth=h,t.lineJoin=c||"bevel");let p=e.endAngle;if(o){Kn(t,e,i,s,p,n);for(let e=0;e<o;++e)t.stroke();isNaN(r)||(p=a+(r%O||O))}g&&function(t,e,i){const{startAngle:s,pixelMargin:n,x:o,y:a,outerRadius:r,innerRadius:l}=e;let h=n/r;t.beginPath(),t.arc(o,a,r,s-h,i+h),l>n?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+E,s-E),t.closePath(),t.clip()}(t,e,p),l.selfJoin&&p-a>=C&&0===f&&"miter"!==c&&function(t,e,i){const{startAngle:s,x:n,y:o,outerRadius:a,innerRadius:r,options:l}=e,{borderWidth:h,borderJoinStyle:c}=l,d=Math.min(h/a,G(s-i));if(t.beginPath(),t.arc(n,o,a-h/2,s+d/2,i-d/2),r>0){const e=Math.min(h/r,G(s-i));t.arc(n,o,r+h/2,i-e/2,s+e/2,!0)}else{const e=Math.min(h/2,a*G(s-i));if("round"===c)t.arc(n,o,e,i-C/2,s+C/2,!0);else if("bevel"===c){const a=2*e*e,r=-a*Math.cos(i+C/2)+n,l=-a*Math.sin(i+C/2)+o,h=a*Math.cos(s+C/2)+n,c=a*Math.sin(s+C/2)+o;t.lineTo(r,l),t.lineTo(h,c)}}t.closePath(),t.moveTo(0,0),t.rect(0,0,t.canvas.width,t.canvas.height),t.clip("evenodd")}(t,e,p),o||(Kn(t,e,i,s,p,n),t.stroke())}function Jn(t,e,i=e){t.lineCap=l(i.borderCapStyle,e.borderCapStyle),t.setLineDash(l(i.borderDash,e.borderDash)),t.lineDashOffset=l(i.borderDashOffset,e.borderDashOffset),t.lineJoin=l(i.borderJoinStyle,e.borderJoinStyle),t.lineWidth=l(i.borderWidth,e.borderWidth),t.strokeStyle=l(i.borderColor,e.borderColor)}function Zn(t,e,i){t.lineTo(i.x,i.y)}function Qn(t,e,i={}){const s=t.length,{start:n=0,end:o=s-1}=i,{start:a,end:r}=e,l=Math.max(n,a),h=Math.min(o,r),c=n<a&&o<a||n>r&&o>r;return{count:s,start:l,loop:e.loop,ilen:h<l&&!c?s+h-l:h-l}}function to(t,e,i,s){const{points:n,options:o}=e,{count:a,start:r,loop:l,ilen:h}=Qn(n,i,s),c=function(t){return t.stepped?Fe:t.tension||"monotone"===t.cubicInterpolationMode?Ve:Zn}(o);let d,u,f,{move:g=!0,reverse:p}=s||{};for(d=0;d<=h;++d)u=n[(r+(p?h-d:d))%a],u.skip||(g?(t.moveTo(u.x,u.y),g=!1):c(t,f,u,p,o.stepped),f=u);return l&&(u=n[(r+(p?h:0))%a],c(t,f,u,p,o.stepped)),!!l}function eo(t,e,i,s){const n=e.points,{count:o,start:a,ilen:r}=Qn(n,i,s),{move:l=!0,reverse:h}=s||{};let c,d,u,f,g,p,m=0,x=0;const b=t=>(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[b(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[b(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(i<f?f=i:i>g&&(g=i),m=(x*m+e)/++x):(_(),t.lineTo(e,i),u=s,x=0,f=g=i),p=i}_()}function io(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?eo:to}const so="function"==typeof Path2D;function no(t,e,i,s){so&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Jn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=io(e);for(const r of n)Jn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class oo extends $s{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t&&"fill"!==t};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;hi(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=zi(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Ii(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?pi:t.tension||"monotone"===t.cubicInterpolationMode?mi:gi}(i);let l,h;for(l=0,h=o.length;l<h;++l){const{start:h,end:c}=o[l],d=n[h],u=n[c];if(d===u){a.push(d);continue}const f=r(d,u,Math.abs((s-d[e])/(u[e]-d[e])),i.stepped);f[e]=t[e],a.push(f)}return 1===a.length?a[0]:a}pathSegment(t,e,i){return io(this)(t,this,e,i)}path(t,e,i){const s=this.segments,n=io(this);let o=this._loop;e=e||0,i=i||this.points.length-e;for(const a of s)o&=n(t,this,a,{start:e,end:e+i-1});return!!o}draw(t,e,i,s){const n=this.options||{};(this.points||[]).length&&n.borderWidth&&(t.save(),no(t,this,i,s),t.restore()),this.animated&&(this._pointsUpdated=!1,this._path=void 0)}}function ao(t,e,i,s){const n=t.options,{[i]:o}=t.getProps([i],s);return Math.abs(e-o)<n.radius+n.hitRadius}function ro(t,e){const{x:i,y:s,base:n,width:o,height:a}=t.getProps(["x","y","base","width","height"],e);let r,l,h,c,d;return t.horizontal?(d=a/2,r=Math.min(i,n),l=Math.max(i,n),h=s-d,c=s+d):(d=o/2,r=i-d,l=i+d,h=Math.min(s,n),c=Math.max(s,n)),{left:r,top:h,right:l,bottom:c}}function lo(t,e,i,s){return t?0:Z(e,i,s)}function ho(t){const e=ro(t),i=e.right-e.left,s=e.bottom-e.top,n=function(t,e,i){const s=t.options.borderWidth,n=t.borderSkipped,o=Mi(s);return{t:lo(n.top,o.top,0,i),r:lo(n.right,o.right,0,e),b:lo(n.bottom,o.bottom,0,i),l:lo(n.left,o.left,0,e)}}(t,i/2,s/2),a=function(t,e,i){const{enableBorderRadius:s}=t.getProps(["enableBorderRadius"]),n=t.options.borderRadius,a=wi(n),r=Math.min(e,i),l=t.borderSkipped,h=s||o(n);return{topLeft:lo(!h||l.top||l.left,a.topLeft,0,r),topRight:lo(!h||l.top||l.right,a.topRight,0,r),bottomLeft:lo(!h||l.bottom||l.left,a.bottomLeft,0,r),bottomRight:lo(!h||l.bottom||l.right,a.bottomRight,0,r)}}(t,i/2,s/2);return{outer:{x:e.left,y:e.top,w:i,h:s,radius:a},inner:{x:e.left+n.l,y:e.top+n.t,w:i-n.l-n.r,h:s-n.t-n.b,radius:{topLeft:Math.max(0,a.topLeft-Math.max(n.t,n.l)),topRight:Math.max(0,a.topRight-Math.max(n.t,n.r)),bottomLeft:Math.max(0,a.bottomLeft-Math.max(n.b,n.l)),bottomRight:Math.max(0,a.bottomRight-Math.max(n.b,n.r))}}}}function co(t,e,i,s){const n=null===e,o=null===i,a=t&&!(n&&o)&&ro(t,s);return a&&(n||tt(e,a.left,a.right))&&(o||tt(i,a.top,a.bottom))}function uo(t,e){t.rect(e.x,e.y,e.w,e.h)}function fo(t,e,i={}){const s=t.x!==i.x?-e:0,n=t.y!==i.y?-e:0,o=(t.x+t.w!==i.x+i.w?e:0)-s,a=(t.y+t.h!==i.y+i.h?e:0)-n;return{x:t.x+s,y:t.y+n,w:t.w+o,h:t.h+a,radius:t.radius}}var go=Object.freeze({__proto__:null,ArcElement:class extends $s{static id="arc";static defaults={borderAlign:"center",borderColor:"#fff",borderDash:[],borderDashOffset:0,borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0,circular:!0,selfJoin:!1};static defaultRoutes={backgroundColor:"backgroundColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.getProps(["x","y"],i),{angle:n,distance:o}=X(s,{x:t,y:e}),{startAngle:a,endAngle:r,innerRadius:h,outerRadius:c,circumference:d}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],i),u=(this.options.spacing+this.options.borderWidth)/2,f=l(d,r-a),g=J(n,a,r)&&a!==r,p=f>=O||g,m=tt(o,h+u,c+u);return p&&m}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/4,n=(e.spacing||0)/2,o=e.circular;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>O?Math.floor(i/O):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();const a=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(a)*s,Math.sin(a)*s);const r=s*(1-Math.sin(Math.min(C,i||0)));t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor,function(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r}=e;let l=e.endAngle;if(o){Kn(t,e,i,s,l,n);for(let e=0;e<o;++e)t.fill();isNaN(r)||(l=a+(r%O||O))}Kn(t,e,i,s,l,n),t.fill()}(t,this,r,n,o),Gn(t,this,r,n,o),t.restore()}},BarElement:class extends $s{static id="bar";static defaults={borderSkipped:"start",borderWidth:0,borderRadius:0,inflateAmount:"auto",pointStyle:void 0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(t){super(),this.options=void 0,this.horizontal=void 0,this.base=void 0,this.width=void 0,this.height=void 0,this.inflateAmount=void 0,t&&Object.assign(this,t)}draw(t){const{inflateAmount:e,options:{borderColor:i,backgroundColor:s}}=this,{inner:n,outer:o}=ho(this),a=(r=o.radius).topLeft||r.topRight||r.bottomLeft||r.bottomRight?He:uo;var r;t.save(),o.w===n.w&&o.h===n.h||(t.beginPath(),a(t,fo(o,e,n)),t.clip(),a(t,fo(n,-e,o)),t.fillStyle=i,t.fill("evenodd")),t.beginPath(),a(t,fo(n,e)),t.fillStyle=s,t.fill(),t.restore()}inRange(t,e,i){return co(this,t,e,i)}inXRange(t,e){return co(this,t,null,e)}inYRange(t,e){return co(this,null,t,e)}getCenterPoint(t){const{x:e,y:i,base:s,horizontal:n}=this.getProps(["x","y","base","horizontal"],t);return{x:n?(e+s)/2:e,y:n?i:(i+s)/2}}getRange(t){return"x"===t?this.width/2:this.height/2}},LineElement:oo,PointElement:class extends $s{static id="point";parsed;skip;stop;static defaults={borderWidth:1,hitRadius:1,hoverBorderWidth:1,hoverRadius:4,pointStyle:"circle",radius:3,rotation:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(t){super(),this.options=void 0,this.parsed=void 0,this.skip=void 0,this.stop=void 0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.options,{x:n,y:o}=this.getProps(["x","y"],i);return Math.pow(t-n,2)+Math.pow(e-o,2)<Math.pow(s.hitRadius+s.radius,2)}inXRange(t,e){return ao(this,t,"x",e)}inYRange(t,e){return ao(this,t,"y",e)}getCenterPoint(t){const{x:e,y:i}=this.getProps(["x","y"],t);return{x:e,y:i}}size(t){let e=(t=t||this.options||{}).radius||0;e=Math.max(e,e&&t.hoverRadius||0);return 2*(e+(e&&t.borderWidth||0))}draw(t,e){const i=this.options;this.skip||i.radius<.1||!Re(this,e,this.size(i)/2)||(t.strokeStyle=i.borderColor,t.lineWidth=i.borderWidth,t.fillStyle=i.backgroundColor,Le(t,i,this.x,this.y))}getRange(){const t=this.options||{};return t.radius+t.hitRadius}}});function po(t,e,i,s){const n=t.indexOf(e);if(-1===n)return((t,e,i,s)=>("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}function mo(t){const e=this.getLabels();return t>=0&&t<e.length?e[t]:t}function xo(t,e,{horizontal:i,minRotation:s}){const n=$(s),o=(i?Math.sin(n):Math.cos(n))||.001,a=.75*e*(""+t).length;return Math.min(e/o,a)}class bo extends tn{constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(t,e){return s(t)||("number"==typeof t||t instanceof Number)&&!isFinite(+t)?null:+t}handleTickRangeOptions(){const{beginAtZero:t}=this.options,{minDefined:e,maxDefined:i}=this.getUserBounds();let{min:s,max:n}=this;const o=t=>s=e?s:t,a=t=>n=i?n:t;if(t){const t=F(s),e=F(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=0===n?1:Math.abs(.05*n);a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const n=function(t,e){const i=[],{bounds:n,step:o,min:a,max:r,precision:l,count:h,maxTicks:c,maxDigits:d,includeBounds:u}=t,f=o||1,g=c-1,{min:p,max:m}=e,x=!s(a),b=!s(r),_=!s(h),y=(m-p)/(d+1);let v,M,w,k,S=B((m-p)/g/f)*f;if(S<1e-14&&!x&&!b)return[{value:p},{value:m}];k=Math.ceil(m/S)-Math.floor(p/S),k>g&&(S=B(k*S/g/f)*f),s(l)||(v=Math.pow(10,l),S=Math.ceil(S*v)/v),"ticks"===n?(M=Math.floor(p/S)*S,w=Math.ceil(m/S)*S):(M=p,w=m),x&&b&&o&&H((r-a)/o,S/1e3)?(k=Math.round(Math.min((r-a)/S,c)),S=(r-a)/k,M=a,w=r):_?(M=x?a:M,w=b?r:w,k=h-1,S=(w-M)/k):(k=(w-M)/S,k=V(k,Math.round(k),S/1e3)?Math.round(k):Math.ceil(k));const P=Math.max(U(S),U(M));v=Math.pow(10,s(l)?P:l),M=Math.round(M*v)/v,w=Math.round(w*v)/v;let D=0;for(x&&(u&&M!==a?(i.push({value:a}),M<a&&D++,V(Math.round((M+D*S)*v)/v,a,xo(a,y,t))&&D++):M<a&&D++);D<k;++D){const t=Math.round((M+D*S)*v)/v;if(b&&t>r)break;i.push({value:t})}return b&&u&&w!==r?i.length&&V(i[i.length-1].value,r,xo(r,y,t))?i[i.length-1].value=r:i.push({value:r}):b&&w!==r||i.push({value:w}),i}({maxTicks:i,bounds:t.bounds,min:t.min,max:t.max,precision:e.precision,step:e.stepSize,count:e.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:e.minRotation||0,includeBounds:!1!==e.includeBounds},this._range||this);return"ticks"===t.bounds&&j(n,this,"value"),t.reverse?(n.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),n}configure(){const t=this.ticks;let e=this.min,i=this.max;if(super.configure(),this.options.offset&&t.length){const s=(i-e)/Math.max(t.length-1,1)/2;e-=s,i+=s}this._startValue=e,this._endValue=i,this._valueRange=i-e}getLabelForValue(t){return ne(t,this.chart.options.locale,this.options.ticks.format)}}class _o extends bo{static id="linear";static defaults={ticks:{callback:ae.formatters.numeric}};determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?t:0,this.max=a(e)?e:1,this.handleTickRangeOptions()}computeTickLimit(){const t=this.isHorizontal(),e=t?this.width:this.height,i=$(this.options.ticks.minRotation),s=(t?Math.sin(i):Math.cos(i))||.001,n=this._resolveTickFontOptions(0);return Math.ceil(e/Math.min(40,n.lineHeight/s))}getPixelForValue(t){return null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getValueForPixel(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange}}const yo=t=>Math.floor(z(t)),vo=(t,e)=>Math.pow(10,yo(t)+e);function Mo(t){return 1===t/Math.pow(10,yo(t))}function wo(t,e,i){const s=Math.pow(10,i),n=Math.floor(t/s);return Math.ceil(e/s)-n}function ko(t,{min:e,max:i}){e=r(t.min,e);const s=[],n=yo(e);let o=function(t,e){let i=yo(e-t);for(;wo(t,e,i)>10;)i++;for(;wo(t,e,i)<10;)i--;return Math.min(i,yo(t))}(e,i),a=o<0?Math.pow(10,Math.abs(o)):1;const l=Math.pow(10,o),h=n>o?Math.pow(10,n):0,c=Math.round((e-h)*a)/a,d=Math.floor((e-h)/l/10)*l*10;let u=Math.floor((c-d)/Math.pow(10,o)),f=r(t.min,Math.round((h+d+u*Math.pow(10,o))*a)/a);for(;f<i;)s.push({value:f,major:Mo(f),significand:u}),u>=10?u=u<15?15:20:u++,u>=20&&(o++,u=2,a=o>=0?1:a),f=Math.round((h+d+u*Math.pow(10,o))*a)/a;const g=r(t.max,f);return s.push({value:g,major:Mo(g),significand:u}),s}class So extends tn{static id="logarithmic";static defaults={ticks:{callback:ae.formatters.logarithmic,major:{enabled:!0}}};constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(t,e){const i=bo.prototype.parse.apply(this,[t,e]);if(0!==i)return a(i)&&i>0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?Math.max(0,t):null,this.max=a(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!a(this._userMin)&&(this.min=t===vo(this.min,0)?vo(this.min,-1):vo(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t;i===s&&(i<=0?(n(1),o(10)):(n(vo(i,-1)),o(vo(s,1)))),i<=0&&n(vo(s,-1)),s<=0&&o(vo(i,1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=ko({min:this._userMin,max:this._userMax},this);return"ticks"===t.bounds&&j(e,this,"value"),t.reverse?(e.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),e}getLabelForValue(t){return void 0===t?"0":ne(t,this.chart.options.locale,this.options.ticks.format)}configure(){const t=this.min;super.configure(),this._startValue=z(t),this._valueRange=z(this.max)-z(t)}getPixelForValue(t){return void 0!==t&&0!==t||(t=this.min),null===t||isNaN(t)?NaN:this.getPixelForDecimal(t===this.min?0:(z(t)-this._startValue)/this._valueRange)}getValueForPixel(t){const e=this.getDecimalForPixel(t);return Math.pow(10,this._startValue+e*this._valueRange)}}function Po(t){const e=t.ticks;if(e.display&&t.display){const t=ki(e.backdropPadding);return l(e.font&&e.font.size,ue.font.size)+t.height}return 0}function Do(t,e,i,s,n){return t===s||t===n?{start:e-i/2,end:e+i/2}:t<s||t>n?{start:e-i,end:e}:{start:e,end:e+i}}function Co(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],o=[],a=t._pointLabels.length,r=t.options.pointLabels,l=r.centerPointLabels?C/a:0;for(let u=0;u<a;u++){const a=r.setContext(t.getPointLabelContext(u));o[u]=a.padding;const f=t.getPointPosition(u,t.drawingArea+o[u],l),g=Si(a.font),p=(h=t.ctx,c=g,d=n(d=t._pointLabels[u])?d:[d],{w:Oe(h,c.string,d),h:d.length*c.lineHeight});s[u]=p;const m=G(t.getIndexAngle(u)+l),x=Math.round(Y(m));Oo(i,e,m,Do(x,f.x,p.w,0,180),Do(x,f.y,p.h,90,270))}var h,c,d;t.setCenterPoint(e.l-i.l,i.r-e.r,e.t-i.t,i.b-e.b),t._pointLabelItems=function(t,e,i){const s=[],n=t._pointLabels.length,o=t.options,{centerPointLabels:a,display:r}=o.pointLabels,l={extra:Po(o)/2,additionalAngle:a?C/n:0};let h;for(let o=0;o<n;o++){l.padding=i[o],l.size=e[o];const n=Ao(t,o,l);s.push(n),"auto"===r&&(n.visible=To(n,h),n.visible&&(h=n))}return s}(t,s,o)}function Oo(t,e,i,s,n){const o=Math.abs(Math.sin(i)),a=Math.abs(Math.cos(i));let r=0,l=0;s.start<e.l?(r=(e.l-s.start)/o,t.l=Math.min(t.l,e.l-r)):s.end>e.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.start<e.t?(l=(e.t-n.start)/a,t.t=Math.min(t.t,e.t-l)):n.end>e.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function Ao(t,e,i){const s=t.drawingArea,{extra:n,additionalAngle:o,padding:a,size:r}=i,l=t.getPointPosition(e,s+n+a,o),h=Math.round(Y(G(l.angle+E))),c=function(t,e,i){90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e);return t}(l.y,r.h,h),d=function(t){if(0===t||180===t)return"center";if(t<180)return"left";return"right"}(h),u=function(t,e,i){"right"===i?t-=e:"center"===i&&(t-=e/2);return t}(l.x,r.w,d);return{visible:!0,x:l.x,y:c,textAlign:d,left:u,top:c,right:u+r.w,bottom:c+r.h}}function To(t,e){if(!e)return!0;const{left:i,top:s,right:n,bottom:o}=t;return!(Re({x:i,y:s},e)||Re({x:i,y:o},e)||Re({x:n,y:s},e)||Re({x:n,y:o},e))}function Lo(t,e,i){const{left:n,top:o,right:a,bottom:r}=i,{backdropColor:l}=e;if(!s(l)){const i=wi(e.borderRadius),s=ki(e.backdropPadding);t.fillStyle=l;const h=n-s.left,c=o-s.top,d=a-n+s.width,u=r-o+s.height;Object.values(i).some((t=>0!==t))?(t.beginPath(),He(t,{x:h,y:c,w:d,h:u,radius:i}),t.fill()):t.fillRect(h,c,d,u)}}function Eo(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,O);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;o<s;o++)i=t.getPointPosition(o,e),n.lineTo(i.x,i.y)}}class Ro extends bo{static id="radialLinear";static defaults={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:ae.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback:t=>t,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(t){super(t),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){const t=this._padding=ki(Po(this.options)/2),e=this.width=this.maxWidth-t.width,i=this.height=this.maxHeight-t.height;this.xCenter=Math.floor(this.left+e/2+t.left),this.yCenter=Math.floor(this.top+i/2+t.top),this.drawingArea=Math.floor(Math.min(e,i)/2)}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!1);this.min=a(t)&&!isNaN(t)?t:0,this.max=a(e)&&!isNaN(e)?e:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/Po(this.options))}generateTickLabels(t){bo.prototype.generateTickLabels.call(this,t),this._pointLabels=this.getLabels().map(((t,e)=>{const i=d(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?Co(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return G(t*(O/(this._pointLabels.length||1))+$(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if(s(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if(s(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t<e.length){const i=e[t];return function(t,e,i){return Ci(t,{label:i,index:e,type:"pointLabel"})}(this.getContext(),t,i)}}getPointPosition(t,e,i=0){const s=this.getIndexAngle(t)-E+i;return{x:Math.cos(s)*e+this.xCenter,y:Math.sin(s)*e+this.yCenter,angle:s}}getPointPositionForValue(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))}getBasePosition(t){return this.getPointPositionForValue(t||0,this.getBaseValue())}getPointLabelPosition(t){const{left:e,top:i,right:s,bottom:n}=this._pointLabelItems[t];return{left:e,top:i,right:s,bottom:n}}drawBackground(){const{backgroundColor:t,grid:{circular:e}}=this.options;if(t){const i=this.ctx;i.save(),i.beginPath(),Eo(this,this.getDistanceFromCenterForValue(this._endValue),e,this._pointLabels.length),i.closePath(),i.fillStyle=t,i.fill(),i.restore()}}drawGrid(){const t=this.ctx,e=this.options,{angleLines:i,grid:s,border:n}=e,o=this._pointLabels.length;let a,r,l;if(e.pointLabels.display&&function(t,e){const{ctx:i,options:{pointLabels:s}}=t;for(let n=e-1;n>=0;n--){const e=t._pointLabelItems[n];if(!e.visible)continue;const o=s.setContext(t.getPointLabelContext(n));Lo(i,o,e);const a=Si(o.font),{x:r,y:l,textAlign:h}=e;Ne(i,t._pointLabels[n],r,l+a.lineHeight/2,a,{color:o.color,textAlign:h,textBaseline:"middle"})}}(this,o),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e||0===e&&this.min<0){r=this.getDistanceFromCenterForValue(t.value);const i=this.getContext(e),a=s.setContext(i),l=n.setContext(i);!function(t,e,i,s,n){const o=t.ctx,a=e.circular,{color:r,lineWidth:l}=e;!a&&!s||!r||!l||i<0||(o.save(),o.strokeStyle=r,o.lineWidth=l,o.setLineDash(n.dash||[]),o.lineDashOffset=n.dashOffset,o.beginPath(),Eo(t,i,a,s),o.closePath(),o.stroke(),o.restore())}(this,a,r,o,l)}})),i.display){for(t.save(),a=o-1;a>=0;a--){const s=i.setContext(this.getPointLabelContext(a)),{color:n,lineWidth:o}=s;o&&n&&(t.lineWidth=o,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,r=this.getDistanceFromCenterForValue(e.reverse?this.min:this.max),l=this.getPointPosition(a,r),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(l.x,l.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&this.min>=0&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=Si(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=ki(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}Ne(t,s.label,0,-n,l,{color:r.color,strokeColor:r.textStrokeColor,strokeWidth:r.textStrokeWidth})})),t.restore()}drawTitle(){}}const Io={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},zo=Object.keys(Io);function Fo(t,e){return t-e}function Vo(t,e){if(s(e))return null;const i=t._adapter,{parser:n,round:o,isoWeekday:r}=t._parseOpts;let l=e;return"function"==typeof n&&(l=n(l)),a(l)||(l="string"==typeof n?i.parse(l,n):i.parse(l)),null===l?null:(o&&(l="week"!==o||!N(r)&&!0!==r?i.startOf(l,o):i.startOf(l,"isoWeek",r)),+l)}function Bo(t,e,i,s){const n=zo.length;for(let o=zo.indexOf(t);o<n-1;++o){const t=Io[zo[o]],n=t.steps?t.steps:Number.MAX_SAFE_INTEGER;if(t.common&&Math.ceil((i-e)/(n*t.size))<=s)return zo[o]}return zo[n-1]}function Wo(t,e,i){if(i){if(i.length){const{lo:s,hi:n}=et(i,e);t[i[s]>=e?i[s]:i[n]]=!0}}else t[e]=!0}function No(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a<o;++a)r=e[a],n[r]=a,s.push({value:r,major:!1});return 0!==o&&i?function(t,e,i,s){const n=t._adapter,o=+n.startOf(e[0].value,s),a=e[e.length-1].value;let r,l;for(r=o;r<=a;r=+n.add(r,1,s))l=i[r],l>=0&&(e[l].major=!0);return e}(t,s,n,i):s}class Ho extends tn{static id="time";static defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",callback:!1,major:{enabled:!1}}};constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e={}){const i=t.time||(t.time={}),s=this._adapter=new In._date(t.adapters.date);s.init(e),b(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:Vo(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:r}=this.getUserBounds();function l(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),r||isNaN(t.max)||(n=Math.max(n,t.max))}o&&r||(l(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||l(this.getMinMax(!1))),s=a(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=a(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=nt(s,n,this.max);return this._unit=e.unit||(i.autoSkip?Bo(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=zo.length-1;o>=zo.indexOf(i);o--){const i=zo[o];if(Io[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return zo[i?zo.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=zo.indexOf(t)+1,i=zo.length;e<i;++e)if(Io[zo[e]].common)return zo[e]}(this._unit):void 0,this.initOffsets(s),t.reverse&&o.reverse(),No(this,o,this._majorUnit)}afterAutoSkip(){this.options.offsetAfterAutoskip&&this.initOffsets(this.ticks.map((t=>+t.value)))}initOffsets(t=[]){let e,i,s=0,n=0;this.options.offset&&t.length&&(e=this.getDecimalForValue(t[0]),s=1===t.length?1-e:(this.getDecimalForValue(t[1])-e)/2,i=this.getDecimalForValue(t[t.length-1]),n=1===t.length?i:(i-this.getDecimalForValue(t[t.length-2]))/2);const o=t.length<3?.5:.25;s=Z(s,0,o),n=Z(n,0,o),this._offsets={start:s,end:n,factor:1/(s+1+n)}}_generate(){const t=this._adapter,e=this.min,i=this.max,s=this.options,n=s.time,o=n.unit||Bo(n.minUnit,e,i,this._getLabelCapacity(e)),a=l(s.ticks.stepSize,1),r="week"===o&&n.isoWeekday,h=N(r)||!0===r,c={};let d,u,f=e;if(h&&(f=+t.startOf(f,"isoWeek",r)),f=+t.startOf(f,h?"day":o),t.diff(i,e,o)>1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const g="data"===s.ticks.source&&this.getDataTimestamps();for(d=f,u=0;d<i;d=+t.add(d,a,o),u++)Wo(c,d,g);return d!==i&&"ticks"!==s.bounds&&1!==u||Wo(c,d,g),Object.keys(c).sort(Fo).map((t=>+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}format(t,e){const i=this.options.time.displayFormats,s=this._unit,n=e||i[s];return this._adapter.format(t,n)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.ticks.callback;if(o)return d(o,[t,e,i],this);const a=n.time.displayFormats,r=this._unit,l=this._majorUnit,h=r&&a[r],c=l&&a[l],u=i[e],f=l&&c&&u&&u.major;return this._adapter.format(t,s||(f?c:h))}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e<i;++e)s=t[e],s.label=this._tickFormatFunction(s.value,e,t)}getDecimalForValue(t){return null===t?NaN:(t-this.min)/(this.max-this.min)}getPixelForValue(t){const e=this._offsets,i=this.getDecimalForValue(t);return this.getPixelForDecimal((e.start+i)*e.factor)}getValueForPixel(t){const e=this._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end;return this.min+i*(this.max-this.min)}_getLabelSize(t){const e=this.options.ticks,i=this.ctx.measureText(t).width,s=$(this.isHorizontal()?e.maxRotation:e.minRotation),n=Math.cos(s),o=Math.sin(s),a=this._resolveTickFontOptions(0).size;return{w:i*n+a*o,h:i*o+a*n}}_getLabelCapacity(t){const e=this.options.time,i=e.displayFormats,s=i[e.unit]||i.millisecond,n=this._tickFormatFunction(t,0,No(this,[t],this._majorUnit),s),o=this._getLabelSize(n),a=Math.floor(this.isHorizontal()?this.width/o.w:this.height/o.h)-1;return a>0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t<e;++t)i=i.concat(s[t].controller.getAllParsedValues(this));return this._cache.data=this.normalize(i)}getLabelTimestamps(){const t=this._cache.labels||[];let e,i;if(t.length)return t;const s=this.getLabels();for(e=0,i=s.length;e<i;++e)t.push(Vo(this,s[e]));return this._cache.labels=this._normalized?t:this.normalize(t)}normalize(t){return lt(t.sort(Fo))}}function jo(t,e,i){let s,n,o,a,r=0,l=t.length-1;i?(e>=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=it(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=it(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}var $o=Object.freeze({__proto__:null,CategoryScale:class extends tn{static id="category";static defaults={ticks:{callback:mo}};constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if(s(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:Z(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:po(i,t,l(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){return mo.call(this,t)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(t){return"number"!=typeof t&&(t=this.parse(t)),null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:_o,LogarithmicScale:So,RadialLinearScale:Ro,TimeScale:Ho,TimeSeriesScale:class extends Ho{static id="timeseries";static defaults=Ho.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=jo(e,this.min),this._tableRange=jo(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o<a;++o)l=t[o],l>=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;o<a;++o)h=s[o+1],r=s[o-1],l=s[o],Math.round((h+r)/2)!==l&&n.push({time:l,pos:o/(a-1)});return n}_generate(){const t=this.min,e=this.max;let i=super.getDataTimestamps();return i.includes(t)&&i.length||i.splice(0,0,t),i.includes(e)&&1!==i.length||i.push(e),i.sort(((t,e)=>t-e))}_getTimestampsForTable(){let t=this._cache.all||[];if(t.length)return t;const e=this.getDataTimestamps(),i=this.getLabelTimestamps();return t=e.length&&i.length?this.normalize(e.concat(i)):e.length?e:i,t=this._cache.all=t,t}getDecimalForValue(t){return(jo(this._table,t)-this._minPos)/this._tableRange}getValueForPixel(t){const e=this._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end;return jo(this._table,i*this._tableRange+this._minPos,!0)}}});const Yo=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],Uo=Yo.map((t=>t.replace("rgb(","rgba(").replace(")",", 0.5)")));function Xo(t){return Yo[t%Yo.length]}function qo(t){return Uo[t%Uo.length]}function Ko(t){let e=0;return(i,s)=>{const n=t.getDatasetMeta(s).controller;n instanceof $n?e=function(t,e){return t.backgroundColor=t.data.map((()=>Xo(e++))),e}(i,e):n instanceof Yn?e=function(t,e){return t.backgroundColor=t.data.map((()=>qo(e++))),e}(i,e):n&&(e=function(t,e){return t.borderColor=Xo(e),t.backgroundColor=qo(e),++e}(i,e))}}function Go(t){let e;for(e in t)if(t[e].borderColor||t[e].backgroundColor)return!0;return!1}var Jo={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(t,e,i){if(!i.enabled)return;const{data:{datasets:s},options:n}=t.config,{elements:o}=n,a=Go(s)||(r=n)&&(r.borderColor||r.backgroundColor)||o&&Go(o)||"rgba(0,0,0,0.1)"!==ue.borderColor||"rgba(0,0,0,0.1)"!==ue.backgroundColor;var r;if(!i.forceOverride&&a)return;const l=Ko(t);s.forEach(l)}};function Zo(t){if(t._decimated){const e=t._data;delete t._decimated,delete t._data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,writable:!0,value:e})}}function Qo(t){t.data.datasets.forEach((t=>{Zo(t)}))}var ta={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void Qo(t);const n=t.width;t.data.datasets.forEach(((e,o)=>{const{_data:a,indexAxis:r}=e,l=t.getDatasetMeta(o),h=a||e.data;if("y"===Pi([r,t.options.indexAxis]))return;if(!l.controller.supportsDecimation)return;const c=t.scales[l.xAxisID];if("linear"!==c.type&&"time"!==c.type)return;if(t.options.parsing)return;let{start:d,count:u}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=Z(it(e,o.axis,a).lo,0,i-1)),s=h?Z(it(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(l,h);if(u<=(i.threshold||4*n))return void Zo(e);let f;switch(s(a)&&(e._data=h,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":f=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;c<o-2;c++){let s,n=0,o=0;const h=Math.floor((c+1)*r)+1+e,m=Math.min(Math.floor((c+2)*r)+1,i)+e,x=m-h;for(s=h;s<m;s++)n+=t[s].x,o+=t[s].y;n/=x,o/=x;const b=Math.floor(c*r)+1+e,_=Math.min(Math.floor((c+1)*r)+1,i)+e,{x:y,y:v}=t[p];for(u=f=-1,s=b;s<_;s++)f=.5*Math.abs((y-n)*(t[s].y-v)-(y-t[s].x)*(o-v)),f>u&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(h,d,u,n,i);break;case"min-max":f=function(t,e,i,n){let o,a,r,l,h,c,d,u,f,g,p=0,m=0;const x=[],b=e+i-1,_=t[e].x,y=t[b].x-_;for(o=e;o<e+i;++o){a=t[o],r=(a.x-_)/y*n,l=a.y;const e=0|r;if(e===h)l<f?(f=l,c=o):l>g&&(g=l,d=o),p=(m*p+a.x)/++m;else{const i=o-1;if(!s(c)&&!s(d)){const e=Math.min(c,d),s=Math.max(c,d);e!==u&&e!==i&&x.push({...t[e],x:p}),s!==u&&s!==i&&x.push({...t[s],x:p})}o>0&&i!==u&&x.push(t[i]),x.push(a),h=e,m=0,f=g=l,c=d=u=o}}return x}(h,d,u,n);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=f}))},destroy(t){Qo(t)}};function ea(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=G(n),o=G(o)),{property:t,start:n,end:o}}function ia(t,e,i){for(;e>t;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function sa(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function na(t,e){let i=[],s=!1;return n(t)?(s=!0,i=t):i=function(t,e){const{x:i=null,y:s=null}=t||{},n=e.points,o=[];return e.segments.forEach((({start:t,end:e})=>{e=ia(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new oo({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function oa(t){return t&&!1!==t.fill}function aa(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!a(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function ra(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=l(i&&i.target,i);void 0===s&&(s=!!e.backgroundColor);if(!1===s||null===s)return!1;if(!0===s)return"origin";return s}(t);if(o(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return a(n)&&Math.floor(n)===n?function(t,e,i,s){"-"!==t&&"+"!==t||(i=e+i);if(i===e||i<0||i>=s)return!1;return i}(s[0],e,n,i):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}function la(t,e,i){const s=[];for(let n=0;n<i.length;n++){const o=i[n],{first:a,last:r,point:l}=ha(o,e,"x");if(!(!l||a&&r))if(a)s.unshift(l);else if(t.push(l),!r)break}t.push(...s)}function ha(t,e,i){const s=t.interpolate(e,i);if(!s)return{};const n=s[i],o=t.segments,a=t.points;let r=!1,l=!1;for(let t=0;t<o.length;t++){const e=o[t],s=a[e.start][i],h=a[e.end][i];if(tt(n,s,h)){r=n===s,l=n===h;break}}return{first:r,last:l,point:s}}class ca{constructor(t){this.x=t.x,this.y=t.y,this.radius=t.radius}pathSegment(t,e,i){const{x:s,y:n,radius:o}=this;return e=e||{start:0,end:O},t.arc(s,n,o,e.end,e.start,!0),!i.bounds}interpolate(t){const{x:e,y:i,radius:s}=this,n=t.angle;return{x:e+Math.cos(n)*s,y:i+Math.sin(n)*s,angle:n}}}function da(t){const{chart:e,fill:i,line:s}=t;if(a(i))return function(t,e){const i=t.getDatasetMeta(e),s=i&&t.isDatasetVisible(e);return s?i.dataset:null}(e,i);if("stack"===i)return function(t){const{scale:e,index:i,line:s}=t,n=[],o=s.segments,a=s.points,r=function(t,e){const i=[],s=t.getMatchingVisibleMetas("line");for(let t=0;t<s.length;t++){const n=s[t];if(n.index===e)break;n.hidden||i.unshift(n.dataset)}return i}(e,i);r.push(na({x:null,y:e.bottom},s));for(let t=0;t<o.length;t++){const e=o[t];for(let t=e.start;t<=e.end;t++)la(n,a[t],r)}return new oo({points:n,options:{}})}(t);if("shape"===i)return!0;const n=function(t){const e=t.scale||{};if(e.getPointPositionForValue)return function(t){const{scale:e,fill:i}=t,s=e.options,n=e.getLabels().length,a=s.reverse?e.max:e.min,r=function(t,e,i){let s;return s="start"===t?i:"end"===t?e.options.reverse?e.min:e.max:o(t)?t.value:e.getBaseValue(),s}(i,e,a),l=[];if(s.grid.circular){const t=e.getPointPositionForValue(0,a);return new ca({x:t.x,y:t.y,radius:e.getDistanceFromCenterForValue(r)})}for(let t=0;t<n;++t)l.push(e.getPointPositionForValue(t,r));return l}(t);return function(t){const{scale:e={},fill:i}=t,s=function(t,e){let i=null;return"start"===t?i=e.bottom:"end"===t?i=e.top:o(t)?i=e.getPixelForValue(t.value):e.getBasePixel&&(i=e.getBasePixel()),i}(i,e);if(a(s)){const t=e.isHorizontal();return{x:t?s:null,y:t?null:s}}return null}(t)}(t);return n instanceof ca?n:na(n,s)}function ua(t,e,i){const s=da(e),{chart:n,index:o,line:a,scale:r,axis:l}=e,h=a.options,c=h.fill,d=h.backgroundColor,{above:u=d,below:f=d}=c||{},g=n.getDatasetMeta(o),p=Ni(n,g);s&&a.points.length&&(Ie(t,i),function(t,e){const{line:i,target:s,above:n,below:o,area:a,scale:r,clip:l}=e,h=i._loop?"angle":e.axis;t.save();let c=o;o!==n&&("x"===h?(fa(t,s,a.top),pa(t,{line:i,target:s,color:n,scale:r,property:h,clip:l}),t.restore(),t.save(),fa(t,s,a.bottom)):"y"===h&&(ga(t,s,a.left),pa(t,{line:i,target:s,color:o,scale:r,property:h,clip:l}),t.restore(),t.save(),ga(t,s,a.right),c=n));pa(t,{line:i,target:s,color:c,scale:r,property:h,clip:l}),t.restore()}(t,{line:a,target:s,above:u,below:f,area:i,scale:r,axis:l,clip:p}),ze(t))}function fa(t,e,i){const{segments:s,points:n}=e;let o=!0,a=!1;t.beginPath();for(const r of s){const{start:s,end:l}=r,h=n[s],c=n[ia(s,l,n)];o?(t.moveTo(h.x,h.y),o=!1):(t.lineTo(h.x,i),t.lineTo(h.x,h.y)),a=!!e.pathSegment(t,r,{move:a}),a?t.closePath():t.lineTo(c.x,i)}t.lineTo(e.first().x,i),t.closePath(),t.clip()}function ga(t,e,i){const{segments:s,points:n}=e;let o=!0,a=!1;t.beginPath();for(const r of s){const{start:s,end:l}=r,h=n[s],c=n[ia(s,l,n)];o?(t.moveTo(h.x,h.y),o=!1):(t.lineTo(i,h.y),t.lineTo(h.x,h.y)),a=!!e.pathSegment(t,r,{move:a}),a?t.closePath():t.lineTo(i,c.y)}t.lineTo(i,e.first().y),t.closePath(),t.clip()}function pa(t,e){const{line:i,target:s,property:n,color:o,scale:a,clip:r}=e,l=function(t,e,i){const s=t.segments,n=t.points,o=e.points,a=[];for(const t of s){let{start:s,end:r}=t;r=ia(s,r,n);const l=ea(i,n[s],n[r],t.loop);if(!e.segments){a.push({source:t,target:l,start:n[s],end:n[r]});continue}const h=Ii(e,l);for(const e of h){const s=ea(i,o[e.start],o[e.end],e.loop),r=Ri(t,n,s);for(const t of r)a.push({source:t,target:e,start:{[i]:sa(l,s,"start",Math.max)},end:{[i]:sa(l,s,"end",Math.min)}})}}return a}(i,s,n);for(const{source:e,target:h,start:c,end:d}of l){const{style:{backgroundColor:l=o}={}}=e,u=!0!==s;t.save(),t.fillStyle=l,ma(t,a,r,u&&ea(n,c,d)),t.beginPath();const f=!!i.pathSegment(t,e);let g;if(u){f?t.closePath():xa(t,s,d,n);const e=!!s.pathSegment(t,h,{move:f,reverse:!0});g=f&&e,g||xa(t,s,c,n)}t.closePath(),t.fill(g?"evenodd":"nonzero"),t.restore()}}function ma(t,e,i,s){const n=e.chart.chartArea,{property:o,start:a,end:r}=s||{};if("x"===o||"y"===o){let e,s,l,h;"x"===o?(e=a,s=n.top,l=r,h=n.bottom):(e=n.left,s=a,l=n.right,h=r),t.beginPath(),i&&(e=Math.max(e,i.left),l=Math.min(l,i.right),s=Math.max(s,i.top),h=Math.min(h,i.bottom)),t.rect(e,s,l-e,h-s),t.clip()}}function xa(t,e,i,s){const n=e.interpolate(i,s);n&&t.lineTo(n.x,n.y)}var ba={id:"filler",afterDatasetsUpdate(t,e,i){const s=(t.data.datasets||[]).length,n=[];let o,a,r,l;for(a=0;a<s;++a)o=t.getDatasetMeta(a),r=o.dataset,l=null,r&&r.options&&r instanceof oo&&(l={visible:t.isDatasetVisible(a),index:a,fill:ra(r,a,s),chart:t,axis:o.controller.options.indexAxis,scale:o.vScale,line:r}),o.$filler=l,n.push(l);for(a=0;a<s;++a)l=n[a],l&&!1!==l.fill&&(l.fill=aa(n,a,i.propagate))},beforeDraw(t,e,i){const s="beforeDraw"===i.drawTime,n=t.getSortedVisibleDatasetMetas(),o=t.chartArea;for(let e=n.length-1;e>=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&i.fill&&ua(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;oa(i)&&ua(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;oa(s)&&"beforeDatasetDraw"===i.drawTime&&ua(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const _a=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=t.pointStyleWidth||Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class ya extends $s{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=d(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=Si(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=_a(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,s,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const{itemWidth:p,itemHeight:m}=function(t,e,i,s,n){const o=function(t,e,i,s){let n=t.text;n&&"string"!=typeof n&&(n=n.reduce(((t,e)=>t.length>e.length?t:e)));return e+i.size/2+s.measureText(n).width}(s,t,e,i),a=function(t,e,i){let s=t;"string"!=typeof e.text&&(s=va(e,i));return s}(n,s,e.lineHeight);return{itemWidth:o,itemHeight:a}}(i,e,n,t,s);o>0&&u+m+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:m},d=Math.max(d,p),u+=m+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:n}}=this,o=Oi(n,this.left,this.width);if(this.isHorizontal()){let n=0,a=ft(i,this.left+s,this.right-this.lineWidths[n]);for(const r of e)n!==r.row&&(n=r.row,a=ft(i,this.left+s,this.right-this.lineWidths[n])),r.top+=this.top+t+s,r.left=o.leftForLtr(o.x(a),r.width),a+=r.width+s}else{let n=0,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height);for(const r of e)r.col!==n&&(n=r.col,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height)),r.top=a,r.left+=this.left+s,r.left=o.leftForLtr(o.x(r.left),r.width),a+=r.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Ie(t,this),this._draw(),ze(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:n,labels:o}=t,a=ue.color,r=Oi(t.rtl,this.left,this.width),h=Si(o.font),{padding:c}=o,d=h.size,u=d/2;let f;this.drawTitle(),s.textAlign=r.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=h.string;const{boxWidth:g,boxHeight:p,itemHeight:m}=_a(o,d),x=this.isHorizontal(),b=this._computeTitleHeight();f=x?{x:ft(n,this.left+c,this.right-i[0]),y:this.top+c+b,line:0}:{x:this.left+c,y:ft(n,this.top+b+c,this.bottom-e[0].height),line:0},Ai(this.ctx,t.textDirection);const _=m+c;this.legendItems.forEach(((y,v)=>{s.strokeStyle=y.fontColor,s.fillStyle=y.fontColor;const M=s.measureText(y.text).width,w=r.textAlign(y.textAlign||(y.textAlign=o.textAlign)),k=g+u+M;let S=f.x,P=f.y;r.setWidth(this.width),x?v>0&&S+k+c>this.right&&(P=f.y+=_,f.line++,S=f.x=ft(n,this.left+c,this.right-i[f.line])):v>0&&P+_>this.bottom&&(S=f.x=S+e[f.line].width+c,f.line++,P=f.y=ft(n,this.top+b+c,this.bottom-e[f.line].height));if(function(t,e,i){if(isNaN(g)||g<=0||isNaN(p)||p<0)return;s.save();const n=l(i.lineWidth,1);if(s.fillStyle=l(i.fillStyle,a),s.lineCap=l(i.lineCap,"butt"),s.lineDashOffset=l(i.lineDashOffset,0),s.lineJoin=l(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=l(i.strokeStyle,a),s.setLineDash(l(i.lineDash,[])),o.usePointStyle){const a={radius:p*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},l=r.xPlus(t,g/2);Ee(s,a,l,e+u,o.pointStyleWidth&&g)}else{const o=e+Math.max((d-p)/2,0),a=r.leftForLtr(t,g),l=wi(i.borderRadius);s.beginPath(),Object.values(l).some((t=>0!==t))?He(s,{x:a,y:o,w:g,h:p,radius:l}):s.rect(a,o,g,p),s.fill(),0!==n&&s.stroke()}s.restore()}(r.x(S),P,y),S=gt(w,S+g+u,x?S+k:this.right,t.rtl),function(t,e,i){Ne(s,i.text,t,e+m/2,h,{strikethrough:i.hidden,textAlign:r.textAlign(i.textAlign)})}(r.x(S),P,y),x)f.x+=k+c;else if("string"!=typeof y.text){const t=h.lineHeight;f.y+=va(y,t)+c}else f.y+=_})),Ti(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=Si(e.font),s=ki(e.padding);if(!e.display)return;const n=Oi(t.rtl,this.left,this.width),o=this.ctx,a=e.position,r=i.size/2,l=s.top+r;let h,c=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),h=this.top+l,c=ft(t.align,c,this.right-d);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);h=l+ft(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const u=ft(a,c,c+d);o.textAlign=n.textAlign(ut(a)),o.textBaseline="middle",o.strokeStyle=e.color,o.fillStyle=e.color,o.font=i.string,Ne(o,e.text,u,h,i)}_computeTitleHeight(){const t=this.options.title,e=Si(t.font),i=ki(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(tt(t,this.left,this.right)&&tt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;i<n.length;++i)if(s=n[i],tt(t,s.left,s.left+s.width)&&tt(e,s.top,s.top+s.height))return this.legendItems[i];return null}handleEvent(t){const e=this.options;if(!function(t,e){if(("mousemove"===t||"mouseout"===t)&&(e.onHover||e.onLeave))return!0;if(e.onClick&&("click"===t||"mouseup"===t))return!0;return!1}(t.type,e))return;const i=this._getLegendItemAt(t.x,t.y);if("mousemove"===t.type||"mouseout"===t.type){const o=this._hoveredItem,a=(n=i,null!==(s=o)&&null!==n&&s.datasetIndex===n.datasetIndex&&s.index===n.index);o&&!a&&d(e.onLeave,[t,o,this],this),this._hoveredItem=i,i&&!a&&d(e.onHover,[t,i,this],this)}else i&&d(e.onClick,[t,i,this],this);var s,n}}function va(t,e){return e*(t.text?t.text.length:0)}var Ma={id:"legend",_element:ya,start(t,e,i){const s=t.legend=new ya({ctx:t.ctx,options:i,chart:t});ls.configure(t,s,i),ls.addBox(t,s)},stop(t){ls.removeBox(t,t.legend),delete t.legend},beforeUpdate(t,e,i){const s=t.legend;ls.configure(t,s,i),s.options=i},afterUpdate(t){const e=t.legend;e.buildLabels(),e.adjustHitBoxes()},afterEvent(t,e){e.replay||t.legend.handleEvent(e.event)},defaults:{display:!0,position:"top",align:"center",fullSize:!0,reverse:!1,weight:1e3,onClick(t,e,i){const s=e.datasetIndex,n=i.chart;n.isDatasetVisible(s)?(n.hide(s),e.hidden=!0):(n.show(s),e.hidden=!1)},onHover:null,onLeave:null,labels:{color:t=>t.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o,useBorderRadius:a,borderRadius:r}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const l=t.controller.getStyle(i?0:void 0),h=ki(l.borderWidth);return{text:e[t.index].label,fillStyle:l.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:l.borderCapStyle,lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:(h.width+h.height)/4,strokeStyle:l.borderColor,pointStyle:s||l.pointStyle,rotation:l.rotation,textAlign:n||l.textAlign,borderRadius:a&&(r||l.borderRadius),datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class wa extends $s{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=n(i.text)?i.text.length:1;this._padding=ki(i.padding);const o=s*Si(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=o:this.width=o}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:n,options:o}=this,a=o.align;let r,l,h,c=0;return this.isHorizontal()?(l=ft(a,i,n),h=e+t,r=n-i):("left"===o.position?(l=i+t,h=ft(a,s,e),c=-.5*C):(l=n-t,h=ft(a,e,s),c=.5*C),r=s-e),{titleX:l,titleY:h,maxWidth:r,rotation:c}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=Si(e.font),s=i.lineHeight/2+this._padding.top,{titleX:n,titleY:o,maxWidth:a,rotation:r}=this._drawArgs(s);Ne(t,e.text,0,0,i,{color:e.color,maxWidth:a,rotation:r,textAlign:ut(e.align),textBaseline:"middle",translation:[n,o]})}}var ka={id:"title",_element:wa,start(t,e,i){!function(t,e){const i=new wa({ctx:t.ctx,options:e,chart:t});ls.configure(t,i,e),ls.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;ls.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;ls.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Sa=new WeakMap;var Pa={id:"subtitle",start(t,e,i){const s=new wa({ctx:t.ctx,options:i,chart:t});ls.configure(t,s,i),ls.addBox(t,s),Sa.set(t,s)},stop(t){ls.removeBox(t,Sa.get(t)),Sa.delete(t)},beforeUpdate(t,e,i){const s=Sa.get(t);ls.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Da={average(t){if(!t.length)return!1;let e,i,s=new Set,n=0,o=0;for(e=0,i=t.length;e<i;++e){const i=t[e].element;if(i&&i.hasValue()){const t=i.tooltipPosition();s.add(t.x),n+=t.y,++o}}if(0===o||0===s.size)return!1;return{x:[...s].reduce(((t,e)=>t+e))/s.size,y:n/o}},nearest(t,e){if(!t.length)return!1;let i,s,n,o=e.x,a=e.y,r=Number.POSITIVE_INFINITY;for(i=0,s=t.length;i<s;++i){const s=t[i].element;if(s&&s.hasValue()){const t=q(e,s.getCenterPoint());t<r&&(r=t,n=s)}}if(n){const t=n.tooltipPosition();o=t.x,a=t.y}return{x:o,y:a}}};function Ca(t,e){return e&&(n(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function Oa(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function Aa(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Ta(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=Si(e.bodyFont),h=Si(e.titleFont),c=Si(e.footerFont),d=o.length,f=n.length,g=s.length,p=ki(e.padding);let m=p.height,x=0,b=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(b+=t.beforeBody.length+t.afterBody.length,d&&(m+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),b){m+=g*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(b-g)*l.lineHeight+(b-1)*e.bodySpacing}f&&(m+=e.footerMarginTop+f*c.lineHeight+(f-1)*e.footerSpacing);let _=0;const y=function(t){x=Math.max(x,i.measureText(t).width+_)};return i.save(),i.font=h.string,u(t.title,y),i.font=l.string,u(t.beforeBody.concat(t.afterBody),y),_=e.displayColors?a+2+e.boxPadding:0,u(s,(t=>{u(t.before,y),u(t.lines,y),u(t.after,y)})),_=0,i.font=c.string,u(t.footer,y),i.restore(),x+=p.width,{width:x,height:m}}function La(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function Ea(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return i<s/2?"top":i>t.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||La(t,e,i,s),yAlign:s}}function Ra(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=wi(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:Z(g,0,s.width-e.width),y:Z(p,0,s.height-e.height)}}function Ia(t,e,i){const s=ki(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function za(t){return Ca([],Oa(t))}function Fa(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}const Va={beforeTitle:e,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex<s)return i[e.dataIndex]}return""},afterTitle:e,beforeBody:e,beforeLabel:e,label(t){if(this&&this.options&&"dataset"===this.options.mode)return t.label+": "+t.formattedValue||t.formattedValue;let e=t.dataset.label||"";e&&(e+=": ");const i=t.formattedValue;return s(i)||(e+=i),e},labelColor(t){const e=t.chart.getDatasetMeta(t.datasetIndex).controller.getStyle(t.dataIndex);return{borderColor:e.borderColor,backgroundColor:e.backgroundColor,borderWidth:e.borderWidth,borderDash:e.borderDash,borderDashOffset:e.borderDashOffset,borderRadius:0}},labelTextColor(){return this.options.bodyColor},labelPointStyle(t){const e=t.chart.getDatasetMeta(t.datasetIndex).controller.getStyle(t.dataIndex);return{pointStyle:e.pointStyle,rotation:e.rotation}},afterLabel:e,afterBody:e,beforeFooter:e,footer:e,afterFooter:e};function Ba(t,e,i,s){const n=t[e].call(i,s);return void 0===n?Va[e].call(i,s):n}class Wa extends $s{static positioners=Da;constructor(t){super(),this.opacity=0,this._active=[],this._eventPosition=void 0,this._size=void 0,this._cachedAnimations=void 0,this._tooltipItems=[],this.$animations=void 0,this.$context=void 0,this.chart=t.chart,this.options=t.options,this.dataPoints=void 0,this.title=void 0,this.beforeBody=void 0,this.body=void 0,this.afterBody=void 0,this.footer=void 0,this.xAlign=void 0,this.yAlign=void 0,this.x=void 0,this.y=void 0,this.height=void 0,this.width=void 0,this.caretX=void 0,this.caretY=void 0,this.labelColors=void 0,this.labelPointStyles=void 0,this.labelTextColors=void 0}initialize(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}_resolveAnimations(){const t=this._cachedAnimations;if(t)return t;const e=this.chart,i=this.options.setContext(this.getContext()),s=i.enabled&&e.options.animation&&i.animations,n=new Ts(this.chart,s);return s._cacheable&&(this._cachedAnimations=Object.freeze(n)),n}getContext(){return this.$context||(this.$context=(t=this.chart.getContext(),e=this,i=this._tooltipItems,Ci(t,{tooltip:e,tooltipItems:i,type:"tooltip"})));var t,e,i}getTitle(t,e){const{callbacks:i}=e,s=Ba(i,"beforeTitle",this,t),n=Ba(i,"title",this,t),o=Ba(i,"afterTitle",this,t);let a=[];return a=Ca(a,Oa(s)),a=Ca(a,Oa(n)),a=Ca(a,Oa(o)),a}getBeforeBody(t,e){return za(Ba(e.callbacks,"beforeBody",this,t))}getBody(t,e){const{callbacks:i}=e,s=[];return u(t,(t=>{const e={before:[],lines:[],after:[]},n=Fa(i,t);Ca(e.before,Oa(Ba(n,"beforeLabel",this,t))),Ca(e.lines,Ba(n,"label",this,t)),Ca(e.after,Oa(Ba(n,"afterLabel",this,t))),s.push(e)})),s}getAfterBody(t,e){return za(Ba(e.callbacks,"afterBody",this,t))}getFooter(t,e){const{callbacks:i}=e,s=Ba(i,"beforeFooter",this,t),n=Ba(i,"footer",this,t),o=Ba(i,"afterFooter",this,t);let a=[];return a=Ca(a,Oa(s)),a=Ca(a,Oa(n)),a=Ca(a,Oa(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;a<r;++a)l.push(Aa(this.chart,e[a]));return t.filter&&(l=l.filter(((e,s,n)=>t.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),u(l,(e=>{const i=Fa(t.callbacks,e);s.push(Ba(i,"labelColor",this,e)),n.push(Ba(i,"labelPointStyle",this,e)),o.push(Ba(i,"labelTextColor",this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=Da[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Ta(this,i),a=Object.assign({},t,e),r=Ea(this.chart,i,a),l=Ra(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=wi(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,x,b,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,b=_+o,y=_-o):(p=d+f,m=p+o,b=_-o,y=_+o),x=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(b=u,_=b-o,p=m-o,x=m+o):(b=u+g,_=b+o,p=m+o,x=m-o),y=b),{x1:p,x2:m,x3:x,y1:b,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Oi(i.rtl,this.x,this.width);for(t.x=Ia(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=Si(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r<n;++r)e.fillText(s[r],l.x(t.x),t.y+o.lineHeight/2),t.y+=o.lineHeight+a,r+1===n&&(t.y+=i.titleMarginBottom-a)}}_drawColorBox(t,e,i,s,n){const a=this.labelColors[i],r=this.labelPointStyles[i],{boxHeight:l,boxWidth:h}=n,c=Si(n.bodyFont),d=Ia(this,"left",n),u=s.x(d),f=l<c.lineHeight?(c.lineHeight-l)/2:0,g=e.y+f;if(n.usePointStyle){const e={radius:Math.min(h,l)/2,pointStyle:r.pointStyle,rotation:r.rotation,borderWidth:1},i=s.leftForLtr(u,h)+h/2,o=g+l/2;t.strokeStyle=n.multiKeyBackground,t.fillStyle=n.multiKeyBackground,Le(t,e,i,o),t.strokeStyle=a.borderColor,t.fillStyle=a.backgroundColor,Le(t,e,i,o)}else{t.lineWidth=o(a.borderWidth)?Math.max(...Object.values(a.borderWidth)):a.borderWidth||1,t.strokeStyle=a.borderColor,t.setLineDash(a.borderDash||[]),t.lineDashOffset=a.borderDashOffset||0;const e=s.leftForLtr(u,h),i=s.leftForLtr(s.xPlus(u,1),h-2),r=wi(a.borderRadius);Object.values(r).some((t=>0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,He(t,{x:e,y:g,w:h,h:l,radius:r}),t.fill(),t.stroke(),t.fillStyle=a.backgroundColor,t.beginPath(),He(t,{x:i,y:g+1,w:h-2,h:l-2,radius:r}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,h,l),t.strokeRect(e,g,h,l),t.fillStyle=a.backgroundColor,t.fillRect(i,g+1,h-2,l-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=Si(i.bodyFont);let d=c.lineHeight,f=0;const g=Oi(i.rtl,this.x,this.width),p=function(i){e.fillText(i,g.x(t.x+f),t.y+d/2),t.y+=d+n},m=g.textAlign(o);let x,b,_,y,v,M,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=Ia(this,m,i),e.fillStyle=i.bodyColor,u(this.beforeBody,p),f=a&&"right"!==m?"center"===o?l/2+h:l+2+h:0,y=0,M=s.length;y<M;++y){for(x=s[y],b=this.labelTextColors[y],e.fillStyle=b,u(x.before,p),_=x.lines,a&&_.length&&(this._drawColorBox(e,t,y,g,i),d=Math.max(c.lineHeight,r)),v=0,w=_.length;v<w;++v)p(_[v]),d=c.lineHeight;u(x.after,p)}f=0,d=c.lineHeight,u(this.afterBody,p),t.y-=n}drawFooter(t,e,i){const s=this.footer,n=s.length;let o,a;if(n){const r=Oi(i.rtl,this.x,this.width);for(t.x=Ia(this,i.footerAlign,i),t.y+=i.footerMarginTop,e.textAlign=r.textAlign(i.footerAlign),e.textBaseline="middle",o=Si(i.footerFont),e.fillStyle=i.footerColor,e.font=o.string,a=0;a<n;++a)e.fillText(s[a],r.x(t.x),t.y+o.lineHeight/2),t.y+=o.lineHeight+i.footerSpacing}}drawBackground(t,e,i,s){const{xAlign:n,yAlign:o}=this,{x:a,y:r}=t,{width:l,height:h}=i,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=wi(s.cornerRadius);e.fillStyle=s.backgroundColor,e.strokeStyle=s.borderColor,e.lineWidth=s.borderWidth,e.beginPath(),e.moveTo(a+c,r),"top"===o&&this.drawCaret(t,e,i,s),e.lineTo(a+l-d,r),e.quadraticCurveTo(a+l,r,a+l,r+d),"center"===o&&"right"===n&&this.drawCaret(t,e,i,s),e.lineTo(a+l,r+h-f),e.quadraticCurveTo(a+l,r+h,a+l-f,r+h),"bottom"===o&&this.drawCaret(t,e,i,s),e.lineTo(a+u,r+h),e.quadraticCurveTo(a,r+h,a,r+h-u),"center"===o&&"left"===n&&this.drawCaret(t,e,i,s),e.lineTo(a,r+c),e.quadraticCurveTo(a,r,a+c,r),e.closePath(),e.fill(),s.borderWidth>0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=Da[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Ta(this,t),a=Object.assign({},i,this._size),r=Ea(e,t,a),l=Ra(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}_willRender(){return!!this.opacity}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=ki(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ai(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),Ti(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!f(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!f(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e.filter((t=>this.chart.data.datasets[t.datasetIndex]&&void 0!==this.chart.getDatasetMeta(t.datasetIndex).controller.getParsed(t.index)));const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=Da[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}var Na={id:"tooltip",_element:Wa,positioners:Da,afterInit(t,e,i){i&&(t.tooltip=new Wa({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip;if(e&&e._willRender()){const i={tooltip:e};if(!1===t.notifyPlugins("beforeTooltipDraw",{...i,cancelable:!0}))return;e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i)}},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:Va},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:t=>"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return Tn.register(Un,$o,go,t),Tn.helpers={...Hi},Tn._adapters=In,Tn.Animation=As,Tn.Animations=Ts,Tn.animator=bt,Tn.controllers=nn.controllers.items,Tn.DatasetController=js,Tn.Element=$s,Tn.elements=go,Tn.Interaction=Ki,Tn.layouts=ls,Tn.platforms=Ds,Tn.Scale=tn,Tn.Ticks=ae,Object.assign(Tn,Un,$o,go,t,Ds),Tn.Chart=Tn,"undefined"!=typeof window&&(window.Chart=Tn),Tn}));14 //# sourceMappingURL=chart.umd. js.map13 */function _t(t){return t+.5|0}const yt=(t,e,i)=>Math.max(Math.min(t,i),e);function vt(t){return yt(_t(2.55*t),0,255)}function Mt(t){return yt(_t(255*t),0,255)}function wt(t){return yt(_t(t/2.55)/100,0,1)}function kt(t){return yt(_t(100*t),0,100)}const St={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Pt=[..."0123456789ABCDEF"],Dt=t=>Pt[15&t],Ct=t=>Pt[(240&t)>>4]+Pt[15&t],Ot=t=>(240&t)>>4==(15&t);function At(t){var e=(t=>Ot(t.r)&&Ot(t.g)&&Ot(t.b)&&Ot(t.a))(t)?Dt:Ct;return t?"#"+e(t.r)+e(t.g)+e(t.b)+((t,e)=>t<255?e(t):"")(t.a,e):void 0}const Tt=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Lt(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function Et(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function Rt(t,e,i){const s=Lt(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function It(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=function(t,e,i,s,n){return t===n?(e-i)/s+(e<i?6:0):e===n?(i-t)/s+2:(t-e)/s+4}(e,i,s,h,n),r=60*r+.5),[0|r,l||0,a]}function zt(t,e,i,s){return(Array.isArray(e)?t(e[0],e[1],e[2]):t(e,i,s)).map(Mt)}function Ft(t,e,i){return zt(Lt,t,e,i)}function Vt(t){return(t%360+360)%360}function Bt(t){const e=Tt.exec(t);let i,s=255;if(!e)return;e[5]!==i&&(s=e[6]?vt(+e[5]):Mt(+e[5]));const n=Vt(+e[2]),o=+e[3]/100,a=+e[4]/100;return i="hwb"===e[1]?function(t,e,i){return zt(Rt,t,e,i)}(n,o,a):"hsv"===e[1]?function(t,e,i){return zt(Et,t,e,i)}(n,o,a):Ft(n,o,a),{r:i[0],g:i[1],b:i[2],a:s}}const Wt={x:"dark",Z:"light",Y:"re",X:"blu",W:"gr",V:"medium",U:"slate",A:"ee",T:"ol",S:"or",B:"ra",C:"lateg",D:"ights",R:"in",Q:"turquois",E:"hi",P:"ro",O:"al",N:"le",M:"de",L:"yello",F:"en",K:"ch",G:"arks",H:"ea",I:"ightg",J:"wh"},Nt={OiceXe:"f0f8ff",antiquewEte:"faebd7",aqua:"ffff",aquamarRe:"7fffd4",azuY:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"0",blanKedOmond:"ffebcd",Xe:"ff",XeviTet:"8a2be2",bPwn:"a52a2a",burlywood:"deb887",caMtXe:"5f9ea0",KartYuse:"7fff00",KocTate:"d2691e",cSO:"ff7f50",cSnflowerXe:"6495ed",cSnsilk:"fff8dc",crimson:"dc143c",cyan:"ffff",xXe:"8b",xcyan:"8b8b",xgTMnPd:"b8860b",xWay:"a9a9a9",xgYF:"6400",xgYy:"a9a9a9",xkhaki:"bdb76b",xmagFta:"8b008b",xTivegYF:"556b2f",xSange:"ff8c00",xScEd:"9932cc",xYd:"8b0000",xsOmon:"e9967a",xsHgYF:"8fbc8f",xUXe:"483d8b",xUWay:"2f4f4f",xUgYy:"2f4f4f",xQe:"ced1",xviTet:"9400d3",dAppRk:"ff1493",dApskyXe:"bfff",dimWay:"696969",dimgYy:"696969",dodgerXe:"1e90ff",fiYbrick:"b22222",flSOwEte:"fffaf0",foYstWAn:"228b22",fuKsia:"ff00ff",gaRsbSo:"dcdcdc",ghostwEte:"f8f8ff",gTd:"ffd700",gTMnPd:"daa520",Way:"808080",gYF:"8000",gYFLw:"adff2f",gYy:"808080",honeyMw:"f0fff0",hotpRk:"ff69b4",RdianYd:"cd5c5c",Rdigo:"4b0082",ivSy:"fffff0",khaki:"f0e68c",lavFMr:"e6e6fa",lavFMrXsh:"fff0f5",lawngYF:"7cfc00",NmoncEffon:"fffacd",ZXe:"add8e6",ZcSO:"f08080",Zcyan:"e0ffff",ZgTMnPdLw:"fafad2",ZWay:"d3d3d3",ZgYF:"90ee90",ZgYy:"d3d3d3",ZpRk:"ffb6c1",ZsOmon:"ffa07a",ZsHgYF:"20b2aa",ZskyXe:"87cefa",ZUWay:"778899",ZUgYy:"778899",ZstAlXe:"b0c4de",ZLw:"ffffe0",lime:"ff00",limegYF:"32cd32",lRF:"faf0e6",magFta:"ff00ff",maPon:"800000",VaquamarRe:"66cdaa",VXe:"cd",VScEd:"ba55d3",VpurpN:"9370db",VsHgYF:"3cb371",VUXe:"7b68ee",VsprRggYF:"fa9a",VQe:"48d1cc",VviTetYd:"c71585",midnightXe:"191970",mRtcYam:"f5fffa",mistyPse:"ffe4e1",moccasR:"ffe4b5",navajowEte:"ffdead",navy:"80",Tdlace:"fdf5e6",Tive:"808000",TivedBb:"6b8e23",Sange:"ffa500",SangeYd:"ff4500",ScEd:"da70d6",pOegTMnPd:"eee8aa",pOegYF:"98fb98",pOeQe:"afeeee",pOeviTetYd:"db7093",papayawEp:"ffefd5",pHKpuff:"ffdab9",peru:"cd853f",pRk:"ffc0cb",plum:"dda0dd",powMrXe:"b0e0e6",purpN:"800080",YbeccapurpN:"663399",Yd:"ff0000",Psybrown:"bc8f8f",PyOXe:"4169e1",saddNbPwn:"8b4513",sOmon:"fa8072",sandybPwn:"f4a460",sHgYF:"2e8b57",sHshell:"fff5ee",siFna:"a0522d",silver:"c0c0c0",skyXe:"87ceeb",UXe:"6a5acd",UWay:"708090",UgYy:"708090",snow:"fffafa",sprRggYF:"ff7f",stAlXe:"4682b4",tan:"d2b48c",teO:"8080",tEstN:"d8bfd8",tomato:"ff6347",Qe:"40e0d0",viTet:"ee82ee",JHt:"f5deb3",wEte:"ffffff",wEtesmoke:"f5f5f5",Lw:"ffff00",LwgYF:"9acd32"};let Ht;function jt(t){Ht||(Ht=function(){const t={},e=Object.keys(Nt),i=Object.keys(Wt);let s,n,o,a,r;for(s=0;s<e.length;s++){for(a=r=e[s],n=0;n<i.length;n++)o=i[n],r=r.replace(o,Wt[o]);o=parseInt(Nt[a],16),t[r]=[o>>16&255,o>>8&255,255&o]}return t}(),Ht.transparent=[0,0,0,0]);const e=Ht[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}const $t=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const Yt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,Ut=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4);function Xt(t,e,i){if(t){let s=It(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=Ft(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function qt(t,e){return t?Object.assign(e||{},t):t}function Kt(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=Mt(t[3]))):(e=qt(t,{r:0,g:0,b:0,a:1})).a=Mt(e.a),e}function Gt(t){return"r"===t.charAt(0)?function(t){const e=$t.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=e[8]?vt(t):yt(255*t,0,255)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?vt(i):yt(i,0,255)),s=255&(e[4]?vt(s):yt(s,0,255)),n=255&(e[6]?vt(n):yt(n,0,255)),{r:i,g:s,b:n,a:o}}}(t):Bt(t)}class Jt{constructor(t){if(t instanceof Jt)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=Kt(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*St[s[1]],g:255&17*St[s[2]],b:255&17*St[s[3]],a:5===o?17*St[s[4]]:255}:7!==o&&9!==o||(n={r:St[s[1]]<<4|St[s[2]],g:St[s[3]]<<4|St[s[4]],b:St[s[5]]<<4|St[s[6]],a:9===o?St[s[7]]<<4|St[s[8]]:255})),i=n||jt(t)||Gt(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=qt(this._rgb);return t&&(t.a=wt(t.a)),t}set rgb(t){this._rgb=Kt(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${wt(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):void 0;var t}hexString(){return this._valid?At(this._rgb):void 0}hslString(){return this._valid?function(t){if(!t)return;const e=It(t),i=e[0],s=kt(e[1]),n=kt(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${wt(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):void 0}mix(t,e){if(t){const i=this.rgb,s=t.rgb;let n;const o=e===n?.5:e,a=2*o-1,r=i.a-s.a,l=((a*r==-1?a:(a+r)/(1+a*r))+1)/2;n=1-l,i.r=255&l*i.r+n*s.r+.5,i.g=255&l*i.g+n*s.g+.5,i.b=255&l*i.b+n*s.b+.5,i.a=o*i.a+(1-o)*s.a,this.rgb=i}return this}interpolate(t,e){return t&&(this._rgb=function(t,e,i){const s=Ut(wt(t.r)),n=Ut(wt(t.g)),o=Ut(wt(t.b));return{r:Mt(Yt(s+i*(Ut(wt(e.r))-s))),g:Mt(Yt(n+i*(Ut(wt(e.g))-n))),b:Mt(Yt(o+i*(Ut(wt(e.b))-o))),a:t.a+i*(e.a-t.a)}}(this._rgb,t._rgb,e)),this}clone(){return new Jt(this.rgb)}alpha(t){return this._rgb.a=Mt(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=_t(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return Xt(this._rgb,2,t),this}darken(t){return Xt(this._rgb,2,-t),this}saturate(t){return Xt(this._rgb,1,t),this}desaturate(t){return Xt(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=It(t);i[0]=Vt(i[0]+e),i=Ft(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function Zt(t){if(t&&"object"==typeof t){const e=t.toString();return"[object CanvasPattern]"===e||"[object CanvasGradient]"===e}return!1}function Qt(t){return Zt(t)?t:new Jt(t)}function te(t){return Zt(t)?t:new Jt(t).saturate(.5).darken(.1).hexString()}const ee=["x","y","borderWidth","radius","tension"],ie=["color","borderColor","backgroundColor"];const se=new Map;function ne(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=se.get(i);return s||(s=new Intl.NumberFormat(t,e),se.set(i,s)),s}(e,i).format(t)}const oe={values:t=>n(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=z(Math.abs(o)),r=isNaN(a)?1:Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),ne(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=i[e].significand||t/Math.pow(10,Math.floor(z(t)));return[1,2,3,5,10,15].includes(s)||e>.8*i.length?oe.numeric.call(this,t,e,i):""}};var ae={formatters:oe};const re=Object.create(null),le=Object.create(null);function he(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;e<s;++e){const s=i[e];t=t[s]||(t[s]=Object.create(null))}return t}function ce(t,e,i){return"string"==typeof e?x(he(t,e),i):x(he(t,""),e)}class de{constructor(t,e){this.animation=void 0,this.backgroundColor="rgba(0,0,0,0.1)",this.borderColor="rgba(0,0,0,0.1)",this.color="#666",this.datasets={},this.devicePixelRatio=t=>t.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>te(e.backgroundColor),this.hoverBorderColor=(t,e)=>te(e.borderColor),this.hoverColor=(t,e)=>te(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t),this.apply(e)}set(t,e){return ce(this,t,e)}get(t){return he(this,t)}describe(t,e){return ce(le,t,e)}override(t,e){return ce(re,t,e)}route(t,e,i,s){const n=he(this,t),a=he(this,i),r="_"+e;Object.defineProperties(n,{[r]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[r],e=a[s];return o(t)?Object.assign({},e,t):l(t,e)},set(t){this[r]=t}}})}apply(t){t.forEach((t=>t(this)))}}var ue=new de({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(t){t.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),t.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:t=>"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),t.set("animations",{colors:{type:"color",properties:ie},numbers:{type:"number",properties:ee}}),t.describe("animations",{_fallback:"animation"}),t.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}})},function(t){t.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(t){t.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(t,e)=>e.lineWidth,tickColor:(t,e)=>e.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:ae.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),t.route("scale.ticks","color","","color"),t.route("scale.grid","color","","borderColor"),t.route("scale.border","color","","borderColor"),t.route("scale.title","color","","color"),t.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t&&"dash"!==t}),t.describe("scales",{_fallback:"scale"}),t.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t})}]);function fe(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ge(t){let e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e}function pe(t,e,i){let s;return"string"==typeof t?(s=parseInt(t,10),-1!==t.indexOf("%")&&(s=s/100*e.parentNode[i])):s=t,s}const me=t=>t.ownerDocument.defaultView.getComputedStyle(t,null);function xe(t,e){return me(t).getPropertyValue(e)}const be=["top","right","bottom","left"];function _e(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=be[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}const ye=(t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot);function ve(t,e){if("native"in t)return t;const{canvas:i,currentDevicePixelRatio:s}=e,n=me(i),o="border-box"===n.boxSizing,a=_e(n,"padding"),r=_e(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.touches,s=i&&i.length?i[0]:t,{offsetX:n,offsetY:o}=s;let a,r,l=!1;if(ye(n,o,t.target))a=n,r=o;else{const t=e.getBoundingClientRect();a=s.clientX-t.left,r=s.clientY-t.top,l=!0}return{x:a,y:r,box:l}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const Me=t=>Math.round(10*t)/10;function we(t,e,i,s){const n=me(t),o=_e(n,"margin"),a=pe(n.maxWidth,t,"clientWidth")||T,r=pe(n.maxHeight,t,"clientHeight")||T,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=t&&ge(t);if(o){const t=o.getBoundingClientRect(),a=me(o),r=_e(a,"border","width"),l=_e(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=pe(a.maxWidth,o,"clientWidth"),n=pe(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||T,maxHeight:n||T}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=_e(n,"border","width"),e=_e(n,"padding");h-=e.width+t.width,c-=e.height+t.height}h=Math.max(0,h-o.width),c=Math.max(0,s?h/s:c-o.height),h=Me(Math.min(h,a,l.maxWidth)),c=Me(Math.min(c,r,l.maxHeight)),h&&!c&&(c=Me(h/2));return(void 0!==e||void 0!==i)&&s&&l.height&&c>l.height&&(c=l.height,h=Me(Math.floor(c*s))),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=Me(t.height*s),o=Me(t.width*s);t.height=Me(t.height),t.width=Me(t.width);const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};fe()&&(window.addEventListener("test",null,e),window.removeEventListener("test",null,e))}catch(t){}return t}();function Pe(t,e){const i=xe(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t){return!t||s(t.size)||s(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Ce(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function Oe(t,e,i,s){let o=(s=s||{}).data=s.data||{},a=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(o=s.data={},a=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let r=0;const l=i.length;let h,c,d,u,f;for(h=0;h<l;h++)if(u=i[h],null==u||n(u)){if(n(u))for(c=0,d=u.length;c<d;c++)f=u[c],null==f||n(f)||(r=Ce(t,o,a,r,f))}else r=Ce(t,o,a,r,u);t.restore();const g=a.length/2;if(g>i.length){for(h=0;h<g;h++)delete o[a[h]];a.splice(0,g)}return r}function Ae(t,e,i){const s=t.currentDevicePixelRatio,n=0!==i?Math.max(i/2,.5):0;return Math.round((e-n)*s)/s+n}function Te(t,e){(e||t)&&((e=e||t.getContext("2d")).save(),e.resetTransform(),e.clearRect(0,0,t.width,t.height),e.restore())}function Le(t,e,i,s){Ee(t,e,i,s,null)}function Ee(t,e,i,s,n){let o,a,r,l,h,c,d,u;const f=e.pointStyle,g=e.rotation,p=e.radius;let m=(g||0)*L;if(f&&"object"==typeof f&&(o=f.toString(),"[object HTMLImageElement]"===o||"[object HTMLCanvasElement]"===o))return t.save(),t.translate(i,s),t.rotate(m),t.drawImage(f,-f.width/2,-f.height/2,f.width,f.height),void t.restore();if(!(isNaN(p)||p<=0)){switch(t.beginPath(),f){default:n?t.ellipse(i,s,n/2,p,0,0,O):t.arc(i,s,p,0,O),t.closePath();break;case"triangle":c=n?n/2:p,t.moveTo(i+Math.sin(m)*c,s-Math.cos(m)*p),m+=I,t.lineTo(i+Math.sin(m)*c,s-Math.cos(m)*p),m+=I,t.lineTo(i+Math.sin(m)*c,s-Math.cos(m)*p),t.closePath();break;case"rectRounded":h=.516*p,l=p-h,a=Math.cos(m+R)*l,d=Math.cos(m+R)*(n?n/2-h:l),r=Math.sin(m+R)*l,u=Math.sin(m+R)*(n?n/2-h:l),t.arc(i-d,s-r,h,m-C,m-E),t.arc(i+u,s-a,h,m-E,m),t.arc(i+d,s+r,h,m,m+E),t.arc(i-u,s+a,h,m+E,m+C),t.closePath();break;case"rect":if(!g){l=Math.SQRT1_2*p,c=n?n/2:l,t.rect(i-c,s-l,2*c,2*l);break}m+=R;case"rectRot":d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+u,s-a),t.lineTo(i+d,s+r),t.lineTo(i-u,s+a),t.closePath();break;case"crossRot":m+=R;case"cross":d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+d,s+r),t.moveTo(i+u,s-a),t.lineTo(i-u,s+a);break;case"star":d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+d,s+r),t.moveTo(i+u,s-a),t.lineTo(i-u,s+a),m+=R,d=Math.cos(m)*(n?n/2:p),a=Math.cos(m)*p,r=Math.sin(m)*p,u=Math.sin(m)*(n?n/2:p),t.moveTo(i-d,s-r),t.lineTo(i+d,s+r),t.moveTo(i+u,s-a),t.lineTo(i-u,s+a);break;case"line":a=n?n/2:Math.cos(m)*p,r=Math.sin(m)*p,t.moveTo(i-a,s-r),t.lineTo(i+a,s+r);break;case"dash":t.moveTo(i,s),t.lineTo(i+Math.cos(m)*(n?n/2:p),s+Math.sin(m)*p);break;case!1:t.closePath()}t.fill(),e.borderWidth>0&&t.stroke()}}function Re(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.x<e.right+i&&t.y>e.top-i&&t.y<e.bottom+i}function Ie(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()}function ze(t){t.restore()}function Fe(t,e,i,s,n){if(!e)return t.lineTo(i.x,i.y);if("middle"===n){const s=(e.x+i.x)/2;t.lineTo(s,e.y),t.lineTo(s,i.y)}else"after"===n!=!!s?t.lineTo(e.x,i.y):t.lineTo(i.x,e.y);t.lineTo(i.x,i.y)}function Ve(t,e,i,s){if(!e)return t.lineTo(i.x,i.y);t.bezierCurveTo(s?e.cp1x:e.cp2x,s?e.cp1y:e.cp2y,s?i.cp2x:i.cp1x,s?i.cp2y:i.cp1y,i.x,i.y)}function Be(t,e,i,s,n){if(n.strikethrough||n.underline){const o=t.measureText(s),a=e-o.actualBoundingBoxLeft,r=e+o.actualBoundingBoxRight,l=i-o.actualBoundingBoxAscent,h=i+o.actualBoundingBoxDescent,c=n.strikethrough?(l+h)/2:h;t.strokeStyle=t.fillStyle,t.beginPath(),t.lineWidth=n.decorationWidth||2,t.moveTo(a,c),t.lineTo(r,c),t.stroke()}}function We(t,e){const i=t.fillStyle;t.fillStyle=e.color,t.fillRect(e.left,e.top,e.width,e.height),t.fillStyle=i}function Ne(t,e,i,o,a,r={}){const l=n(e)?e:[e],h=r.strokeWidth>0&&""!==r.strokeColor;let c,d;for(t.save(),t.font=a.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]),s(e.rotation)||t.rotate(e.rotation),e.color&&(t.fillStyle=e.color),e.textAlign&&(t.textAlign=e.textAlign),e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,r),c=0;c<l.length;++c)d=l[c],r.backdrop&&We(t,r.backdrop),h&&(r.strokeColor&&(t.strokeStyle=r.strokeColor),s(r.strokeWidth)||(t.lineWidth=r.strokeWidth),t.strokeText(d,i,o,r.maxWidth)),t.fillText(d,i,o,r.maxWidth),Be(t,i,o,d,r),o+=Number(a.lineHeight);t.restore()}function He(t,e){const{x:i,y:s,w:n,h:o,radius:a}=e;t.arc(i+a.topLeft,s+a.topLeft,a.topLeft,1.5*C,C,!0),t.lineTo(i,s+o-a.bottomLeft),t.arc(i+a.bottomLeft,s+o-a.bottomLeft,a.bottomLeft,C,E,!0),t.lineTo(i+n-a.bottomRight,s+o),t.arc(i+n-a.bottomRight,s+o-a.bottomRight,a.bottomRight,E,0,!0),t.lineTo(i+n,s+a.topRight),t.arc(i+n-a.topRight,s+a.topRight,a.topRight,0,-E,!0),t.lineTo(i+a.topLeft,s)}function je(t,e=[""],i,s,n=(()=>t[0])){const o=i||t;void 0===s&&(s=ti("_fallback",t));const a={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:o,_fallback:s,_getTarget:n,override:i=>je([i,...t],e,o,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>qe(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=ti(Ue(o,t),i),void 0!==n)return Xe(t,n)?Ze(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>ei(t).includes(e),ownKeys:t=>ei(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function $e(t,e,i,s){const a={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:Ye(t,s),setContext:e=>$e(t,e,i,s),override:n=>$e(t.override(n),e,i,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>qe(t,e,(()=>function(t,e,i){const{_proxy:s,_context:a,_subProxy:r,_descriptors:l}=t;let h=s[e];S(h)&&l.isScriptable(e)&&(h=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t);let l=e(o,a||s);r.delete(t),Xe(t,l)&&(l=Ze(n._scopes,n,t,l));return l}(e,h,t,i));n(h)&&h.length&&(h=function(t,e,i,s){const{_proxy:n,_context:a,_subProxy:r,_descriptors:l}=i;if(void 0!==a.index&&s(t))return e[a.index%e.length];if(o(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const o of i){const i=Ze(s,n,t,o);e.push($e(i,a,r&&r[t],l))}}return e}(e,h,t,l.isIndexable));Xe(e,h)&&(h=$e(h,a,r&&r[e],l));return h}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function Ye(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:S(i)?i:()=>i,isIndexable:S(s)?s:()=>s}}const Ue=(t,e)=>t?t+w(e):e,Xe=(t,e)=>o(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function qe(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e)||"constructor"===e)return t[e];const s=i();return t[e]=s,s}function Ke(t,e,i){return S(t)?t(e,i):t}const Ge=(t,e)=>!0===t?e:"string"==typeof t?M(e,t):void 0;function Je(t,e,i,s,n){for(const o of e){const e=Ge(i,o);if(e){t.add(e);const o=Ke(e._fallback,i,n);if(void 0!==o&&o!==i&&o!==s)return o}else if(!1===e&&void 0!==s&&i!==s)return null}return!1}function Ze(t,e,i,s){const a=e._rootScopes,r=Ke(e._fallback,i,s),l=[...t,...a],h=new Set;h.add(s);let c=Qe(h,l,i,r||i,s);return null!==c&&((void 0===r||r===i||(c=Qe(h,l,r,c,s),null!==c))&&je(Array.from(h),[""],a,r,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const a=s[e];if(n(a)&&o(i))return i;return a||{}}(e,i,s))))}function Qe(t,e,i,s,n){for(;i;)i=Je(t,e,i,s,n);return i}function ti(t,e){for(const i of e){if(!i)continue;const e=i[t];if(void 0!==e)return e}}function ei(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}function ii(t,e,i,s){const{iScale:n}=t,{key:o="r"}=this._parsing,a=new Array(s);let r,l,h,c;for(r=0,l=s;r<l;++r)h=r+i,c=e[h],a[r]={r:n.parse(M(c,o),h)};return a}const si=Number.EPSILON||1e-14,ni=(t,e)=>e<t.length&&!t[e].skip&&t[e],oi=t=>"x"===t?"y":"x";function ai(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=q(o,n),l=q(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function ri(t,e="x"){const i=oi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=ni(t,0);for(a=0;a<s;++a)if(r=l,l=h,h=ni(t,a+1),l){if(h){const t=h[e]-l[e];n[a]=0!==t?(h[i]-l[i])/t:0}o[a]=r?h?F(n[a-1])!==F(n[a])?0:(n[a-1]+n[a])/2:n[a-1]:n[a]}!function(t,e,i){const s=t.length;let n,o,a,r,l,h=ni(t,0);for(let c=0;c<s-1;++c)l=h,h=ni(t,c+1),l&&h&&(V(e[c],0,si)?i[c]=i[c+1]=0:(n=i[c]/e[c],o=i[c+1]/e[c],r=Math.pow(n,2)+Math.pow(o,2),r<=9||(a=3/Math.sqrt(r),i[c]=n*a*e[c],i[c+1]=o*a*e[c])))}(t,n,o),function(t,e,i="x"){const s=oi(i),n=t.length;let o,a,r,l=ni(t,0);for(let h=0;h<n;++h){if(a=r,r=l,l=ni(t,h+1),!r)continue;const n=r[i],c=r[s];a&&(o=(n-a[i])/3,r[`cp1${i}`]=n-o,r[`cp1${s}`]=c-o*e[h]),l&&(o=(l[i]-n)/3,r[`cp2${i}`]=n+o,r[`cp2${s}`]=c+o*e[h])}}(t,o,e)}function li(t,e,i){return Math.max(Math.min(t,i),e)}function hi(t,e,i,s,n){let o,a,r,l;if(e.spanGaps&&(t=t.filter((t=>!t.skip))),"monotone"===e.cubicInterpolationMode)ri(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o<a;++o)r=t[o],l=ai(i,r,t[Math.min(o+1,a-(s?0:1))%a],e.tension),r.cp1x=l.previous.x,r.cp1y=l.previous.y,r.cp2x=l.next.x,r.cp2y=l.next.y,i=r}e.capBezierPoints&&function(t,e){let i,s,n,o,a,r=Re(t[0],e);for(i=0,s=t.length;i<s;++i)a=o,o=r,r=i<s-1&&Re(t[i+1],e),o&&(n=t[i],a&&(n.cp1x=li(n.cp1x,e.left,e.right),n.cp1y=li(n.cp1y,e.top,e.bottom)),r&&(n.cp2x=li(n.cp2x,e.left,e.right),n.cp2y=li(n.cp2y,e.top,e.bottom)))}(t,i)}const ci=t=>0===t||1===t,di=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*O/i),ui=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*O/i)+1,fi={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*E),easeOutSine:t=>Math.sin(t*E),easeInOutSine:t=>-.5*(Math.cos(C*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>ci(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>ci(t)?t:di(t,.075,.3),easeOutElastic:t=>ci(t)?t:ui(t,.075,.3),easeInOutElastic(t){const e=.1125;return ci(t)?t:t<.5?.5*di(2*t,e,.45):.5+.5*ui(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-fi.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*fi.easeInBounce(2*t):.5*fi.easeOutBounce(2*t-1)+.5};function gi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function pi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function mi(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=gi(t,n,i),r=gi(n,o,i),l=gi(o,e,i),h=gi(a,r,i),c=gi(r,l,i);return gi(h,c,i)}const xi=/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/,bi=/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;function _i(t,e){const i=(""+t).match(xi);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}const yi=t=>+t||0;function vi(t,e){const i={},s=o(e),n=s?Object.keys(e):e,a=o(t)?s?i=>l(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=yi(a(t));return i}function Mi(t){return vi(t,{top:"y",right:"x",bottom:"y",left:"x"})}function wi(t){return vi(t,["topLeft","topRight","bottomLeft","bottomRight"])}function ki(t){const e=Mi(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function Si(t,e){t=t||{},e=e||ue.font;let i=l(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=l(t.style,e.style);s&&!(""+s).match(bi)&&(console.warn('Invalid font style specified: "'+s+'"'),s=void 0);const n={family:l(t.family,e.family),lineHeight:_i(l(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:l(t.weight,e.weight),string:""};return n.string=De(n),n}function Pi(t,e,i,s){let o,a,r,l=!0;for(o=0,a=t.length;o<a;++o)if(r=t[o],void 0!==r&&(void 0!==e&&"function"==typeof r&&(r=r(e),l=!1),void 0!==i&&n(r)&&(r=r[i%r.length],l=!1),void 0!==r))return s&&!l&&(s.cacheable=!1),r}function Di(t,e,i){const{min:s,max:n}=t,o=c(e,(n-s)/2),a=(t,e)=>i&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ci(t,e){return Object.assign(Object.create(t),e)}function Oi(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ai(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function Ti(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Li(t){return"angle"===t?{between:J,compare:K,normalize:G}:{between:tt,compare:(t,e)=>t-e,normalize:t=>t}}function Ei({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Ri(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Li(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Li(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;h<c&&a(r(e[d%l][s]),n,o);++h)d--,u--;d%=l,u%=l}return u<d&&(u+=l),{start:d,end:u,loop:f,style:t.style}}(t,e,i),g=[];let p,m,x,b=!1,_=null;const y=()=>b||l(n,x,p)&&0!==r(n,x),v=()=>!b||0===r(o,p)||l(o,x,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==x&&(b=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Ei({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,x=p));return null!==_&&g.push(Ei({start:_,end:d,loop:u,count:a,style:f})),g}function Ii(t,e){const i=[],s=t.segments;for(let n=0;n<s.length;n++){const o=Ri(s[n],t.points,e);o.length&&i.push(...o)}return i}function zi(t,e){const i=t.points,s=t.options.spanGaps,n=i.length;if(!n)return[];const o=!!t._loop,{start:a,end:r}=function(t,e,i,s){let n=0,o=e-1;if(i&&!s)for(;n<e&&!t[n].skip;)n++;for(;n<e&&t[n].skip;)n++;for(n%=e,i&&(o+=n);o>n&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Fi(t,[{start:a,end:r,loop:o}],i,e);return Fi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,r<a?r+n:r,!!t._fullLoop&&0===a&&r===n-1),i,e)}function Fi(t,e,i,s){return s&&s.setContext&&i?function(t,e,i,s){const n=t._chart.getContext(),o=Vi(t.options),{_datasetIndex:a,options:{spanGaps:r}}=t,l=i.length,h=[];let c=o,d=e[0].start,u=d;function f(t,e,s,n){const o=r?-1:1;if(t!==e){for(t+=l;i[t%l].skip;)t-=o;for(;i[e%l].skip;)e+=o;t%l!=e%l&&(h.push({start:t%l,end:e%l,loop:s,style:n}),c=n,d=e%l)}}for(const t of e){d=r?d:t.start;let e,o=i[d%l];for(u=d+1;u<=t.end;u++){const r=i[u%l];e=Vi(s.setContext(Ci(n,{type:"segment",p0:o,p1:r,p0DataIndex:(u-1)%l,p1DataIndex:u%l,datasetIndex:a}))),Bi(e,c)&&f(d,u-1,t.loop,c),o=r,c=e}d<u-1&&f(d,u-1,t.loop,c)}return h}(t,e,i,s):e}function Vi(t){return{backgroundColor:t.backgroundColor,borderCapStyle:t.borderCapStyle,borderDash:t.borderDash,borderDashOffset:t.borderDashOffset,borderJoinStyle:t.borderJoinStyle,borderWidth:t.borderWidth,borderColor:t.borderColor}}function Bi(t,e){if(!e)return!1;const i=[],s=function(t,e){return Zt(e)?(i.includes(e)||i.push(e),i.indexOf(e)):e};return JSON.stringify(t,s)!==JSON.stringify(e,s)}function Wi(t,e,i){return t.options.clip?t[i]:e[i]}function Ni(t,e){const i=e._clip;if(i.disabled)return!1;const s=function(t,e){const{xScale:i,yScale:s}=t;return i&&s?{left:Wi(i,e,"left"),right:Wi(i,e,"right"),top:Wi(s,e,"top"),bottom:Wi(s,e,"bottom")}:e}(e,t.chartArea);return{left:!1===i.left?0:s.left-(!0===i.left?0:i.left),right:!1===i.right?t.width:s.right+(!0===i.right?0:i.right),top:!1===i.top?0:s.top-(!0===i.top?0:i.top),bottom:!1===i.bottom?t.height:s.bottom+(!0===i.bottom?0:i.bottom)}}var Hi=Object.freeze({__proto__:null,HALF_PI:E,INFINITY:T,PI:C,PITAU:A,QUARTER_PI:R,RAD_PER_DEG:L,TAU:O,TWO_THIRDS_PI:I,_addGrace:Di,_alignPixel:Ae,_alignStartEnd:ft,_angleBetween:J,_angleDiff:K,_arrayUnique:lt,_attachContext:$e,_bezierCurveTo:Ve,_bezierInterpolation:mi,_boundSegment:Ri,_boundSegments:Ii,_capitalize:w,_computeSegments:zi,_createResolver:je,_decimalPlaces:U,_deprecated:function(t,e,i,s){void 0!==e&&console.warn(t+': "'+i+'" is deprecated. Please use "'+s+'" instead')},_descriptors:Ye,_elementsEqual:f,_factorize:W,_filterBetween:nt,_getParentNode:ge,_getStartAndCountOfVisiblePoints:pt,_int16Range:Q,_isBetween:tt,_isClickEvent:D,_isDomSupported:fe,_isPointInArea:Re,_limitValue:Z,_longestText:Oe,_lookup:et,_lookupByKey:it,_measureText:Ce,_merger:m,_mergerIf:_,_normalizeAngle:G,_parseObjectDataRadialScale:ii,_pointInLine:gi,_readValueToProps:vi,_rlookupByKey:st,_scaleRangesChanged:mt,_setMinAndMaxByKey:j,_splitKey:v,_steppedInterpolation:pi,_steppedLineTo:Fe,_textX:gt,_toLeftRightCenter:ut,_updateBezierControlPoints:hi,addRoundedRectPath:He,almostEquals:V,almostWhole:H,callback:d,clearCanvas:Te,clipArea:Ie,clone:g,color:Qt,createContext:Ci,debounce:dt,defined:k,distanceBetweenPoints:q,drawPoint:Le,drawPointLegend:Ee,each:u,easingEffects:fi,finiteOrDefault:r,fontString:function(t,e,i){return e+" "+t+"px "+i},formatNumber:ne,getAngleFromPoint:X,getDatasetClipArea:Ni,getHoverColor:te,getMaximumSize:we,getRelativePosition:ve,getRtlAdapter:Oi,getStyle:xe,isArray:n,isFinite:a,isFunction:S,isNullOrUndef:s,isNumber:N,isObject:o,isPatternOrGradient:Zt,listenArrayEvents:at,log10:z,merge:x,mergeIf:b,niceNum:B,noop:e,overrideTextDirection:Ai,readUsedSize:Pe,renderText:Ne,requestAnimFrame:ht,resolve:Pi,resolveObjectKey:M,restoreTextDirection:Ti,retinaScale:ke,setsEqual:P,sign:F,splineCurve:ai,splineCurveMonotone:ri,supportsEventListenerOptions:Se,throttled:ct,toDegrees:Y,toDimension:c,toFont:Si,toFontString:De,toLineHeight:_i,toPadding:ki,toPercentage:h,toRadians:$,toTRBL:Mi,toTRBLCorners:wi,uid:i,unclipArea:ze,unlistenArrayEvents:rt,valueOrDefault:l});function ji(t,e,i,n){const{controller:o,data:a,_sorted:r}=t,l=o._cachedMeta.iScale,h=t.dataset&&t.dataset.options?t.dataset.options.spanGaps:null;if(l&&e===l.axis&&"r"!==e&&r&&a.length){const r=l._reversePixels?st:it;if(!n){const n=r(a,e,i);if(h){const{vScale:e}=o._cachedMeta,{_parsed:i}=t,a=i.slice(0,n.lo+1).reverse().findIndex((t=>!s(t[e.axis])));n.lo-=Math.max(0,a);const r=i.slice(n.hi).findIndex((t=>!s(t[e.axis])));n.hi+=Math.max(0,r)}return n}if(o._sharedOptions){const t=a[0],s="function"==typeof t.getRange&&t.getRange(e);if(s){const t=r(a,e,i-s),n=r(a,e,i+s);return{lo:t.lo,hi:n.hi}}}}return{lo:0,hi:a.length-1}}function $i(t,e,i,s,n){const o=t.getSortedVisibleDatasetMetas(),a=i[e];for(let t=0,i=o.length;t<i;++t){const{index:i,data:r}=o[t],{lo:l,hi:h}=ji(o[t],e,a,n);for(let t=l;t<=h;++t){const e=r[t];e.skip||s(e,i,t)}}}function Yi(t,e,i,s,n){const o=[];if(!n&&!t.isPointInArea(e))return o;return $i(t,i,e,(function(i,a,r){(n||Re(i,t.chartArea,0))&&i.inRange(e.x,e.y,s)&&o.push({element:i,datasetIndex:a,index:r})}),!0),o}function Ui(t,e,i,s,n,o){let a=[];const r=function(t){const e=-1!==t.indexOf("x"),i=-1!==t.indexOf("y");return function(t,s){const n=e?Math.abs(t.x-s.x):0,o=i?Math.abs(t.y-s.y):0;return Math.sqrt(Math.pow(n,2)+Math.pow(o,2))}}(i);let l=Number.POSITIVE_INFINITY;return $i(t,i,e,(function(i,h,c){const d=i.inRange(e.x,e.y,n);if(s&&!d)return;const u=i.getCenterPoint(n);if(!(!!o||t.isPointInArea(u))&&!d)return;const f=r(e,u);f<l?(a=[{element:i,datasetIndex:h,index:c}],l=f):f===l&&a.push({element:i,datasetIndex:h,index:c})})),a}function Xi(t,e,i,s,n,o){return o||t.isPointInArea(e)?"r"!==i||s?Ui(t,e,i,s,n,o):function(t,e,i,s){let n=[];return $i(t,i,e,(function(t,i,o){const{startAngle:a,endAngle:r}=t.getProps(["startAngle","endAngle"],s),{angle:l}=X(t,{x:e.x,y:e.y});J(l,a,r)&&n.push({element:t,datasetIndex:i,index:o})})),n}(t,e,i,n):[]}function qi(t,e,i,s,n){const o=[],a="x"===i?"inXRange":"inYRange";let r=!1;return $i(t,i,e,((t,s,l)=>{t[a]&&t[a](e[i],n)&&(o.push({element:t,datasetIndex:s,index:l}),r=r||t.inRange(e.x,e.y,n))})),s&&!r?[]:o}var Ki={evaluateInteractionItems:$i,modes:{index(t,e,i,s){const n=ve(e,t),o=i.axis||"x",a=i.includeInvisible||!1,r=i.intersect?Yi(t,n,o,s,a):Xi(t,n,o,!1,s,a),l=[];return r.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=r[0].index,i=t.data[e];i&&!i.skip&&l.push({element:i,datasetIndex:t.index,index:e})})),l):[]},dataset(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;let r=i.intersect?Yi(t,n,o,s,a):Xi(t,n,o,!1,s,a);if(r.length>0){const e=r[0].datasetIndex,i=t.getDatasetMeta(e).data;r=[];for(let t=0;t<i.length;++t)r.push({element:i[t],datasetIndex:e,index:t})}return r},point:(t,e,i,s)=>Yi(t,ve(e,t),i.axis||"xy",s,i.includeInvisible||!1),nearest(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;return Xi(t,n,o,i.intersect,s,a)},x:(t,e,i,s)=>qi(t,ve(e,t),"x",i.intersect,s),y:(t,e,i,s)=>qi(t,ve(e,t),"y",i.intersect,s)}};const Gi=["left","top","right","bottom"];function Ji(t,e){return t.filter((t=>t.pos===e))}function Zi(t,e){return t.filter((t=>-1===Gi.indexOf(t.pos)&&t.box.axis===e))}function Qi(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function ts(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!Gi.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o<a;++o){r=t[o];const{fullSize:a}=r.box,l=i[r.stack],h=l&&r.stackWeight/l.weight;r.horizontal?(r.width=h?h*s:a&&e.availableWidth,r.height=n):(r.width=s,r.height=h?h*n:a&&e.availableHeight)}return i}function es(t,e,i,s){return Math.max(t[i],e[i])+Math.max(t[s],e[s])}function is(t,e){t.top=Math.max(t.top,e.top),t.left=Math.max(t.left,e.left),t.bottom=Math.max(t.bottom,e.bottom),t.right=Math.max(t.right,e.right)}function ss(t,e,i,s){const{pos:n,box:a}=i,r=t.maxPadding;if(!o(n)){i.size&&(t[n]-=i.size);const e=s[i.stack]||{size:0,count:1};e.size=Math.max(e.size,i.horizontal?a.height:a.width),i.size=e.size/e.count,t[n]+=i.size}a.getPadding&&is(r,a.getPadding());const l=Math.max(0,e.outerWidth-es(r,t,"left","right")),h=Math.max(0,e.outerHeight-es(r,t,"top","bottom")),c=l!==t.w,d=h!==t.h;return t.w=l,t.h=h,i.horizontal?{same:c,other:d}:{same:d,other:c}}function ns(t,e){const i=e.maxPadding;function s(t){const s={left:0,top:0,right:0,bottom:0};return t.forEach((t=>{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function os(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;o<a;++o){r=t[o],l=r.box,l.update(r.width||e.w,r.height||e.h,ns(r.horizontal,e));const{same:a,other:d}=ss(e,i,r,s);h|=a&&n.length,c=c||d,l.fullSize||n.push(r)}return h&&os(n,e,i,s)||c}function as(t,e,i,s,n){t.top=i,t.left=e,t.right=e+s,t.bottom=i+n,t.width=s,t.height=n}function rs(t,e,i,s){const n=i.padding;let{x:o,y:a}=e;for(const r of t){const t=r.box,l=s[r.stack]||{count:1,placed:0,weight:1},h=r.stackWeight/l.weight||1;if(r.horizontal){const s=e.w*h,o=l.size||t.height;k(l.start)&&(a=l.start),t.fullSize?as(t,n.left,a,i.outerWidth-n.right-n.left,o):as(t,e.left+l.placed,a,s,o),l.start=a,l.placed+=s,a=t.bottom}else{const s=e.h*h,a=l.size||t.width;k(l.start)&&(o=l.start),t.fullSize?as(t,o,n.top,a,i.outerHeight-n.bottom-n.top):as(t,o,e.top+l.placed,a,s),l.start=o,l.placed+=s,o=t.right}}e.x=o,e.y=a}var ls={addBox(t,e){t.boxes||(t.boxes=[]),e.fullSize=e.fullSize||!1,e.position=e.position||"top",e.weight=e.weight||0,e._layers=e._layers||function(){return[{z:0,draw(t){e.draw(t)}}]},t.boxes.push(e)},removeBox(t,e){const i=t.boxes?t.boxes.indexOf(e):-1;-1!==i&&t.boxes.splice(i,1)},configure(t,e,i){e.fullSize=i.fullSize,e.position=i.position,e.weight=i.weight},update(t,e,i,s){if(!t)return;const n=ki(t.options.layout.padding),o=Math.max(e-n.width,0),a=Math.max(i-n.height,0),r=function(t){const e=function(t){const e=[];let i,s,n,o,a,r;for(i=0,s=(t||[]).length;i<s;++i)n=t[i],({position:o,options:{stack:a,stackWeight:r=1}}=n),e.push({index:i,box:n,pos:o,horizontal:n.isHorizontal(),weight:n.weight,stack:a&&o+a,stackWeight:r});return e}(t),i=Qi(e.filter((t=>t.box.fullSize)),!0),s=Qi(Ji(e,"left"),!0),n=Qi(Ji(e,"right")),o=Qi(Ji(e,"top"),!0),a=Qi(Ji(e,"bottom")),r=Zi(e,"x"),l=Zi(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Ji(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;u(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),f=Object.assign({},n);is(f,ki(s));const g=Object.assign({maxPadding:f,w:o,h:a,x:n.left,y:n.top},n),p=ts(l.concat(h),d);os(r.fullSize,g,d,p),os(l,g,d,p),os(h,g,d,p)&&os(l,g,d,p),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(g),rs(r.leftAndTop,g,d,p),g.x+=g.w,g.y+=g.h,rs(r.rightAndBottom,g,d,p),t.chartArea={left:g.left,top:g.top,right:g.left+g.w,bottom:g.top+g.h,height:g.h,width:g.w},u(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(g.w,g.h,{left:0,top:0,right:0,bottom:0})}))}};class hs{acquireContext(t,e){}releaseContext(t){return!1}addEventListener(t,e,i){}removeEventListener(t,e,i){}getDevicePixelRatio(){return 1}getMaximumSize(t,e,i,s){return e=Math.max(0,e||t.width),i=i||t.height,{width:e,height:Math.max(0,s?Math.floor(e/s):i)}}isAttached(t){return!0}updateConfig(t){}}class cs extends hs{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const ds="$chartjs",us={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},fs=t=>null===t||""===t;const gs=!!Se&&{passive:!0};function ps(t,e,i){t&&t.canvas&&t.canvas.removeEventListener(e,i,gs)}function ms(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function xs(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||ms(i.addedNodes,s),e=e&&!ms(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function bs(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||ms(i.removedNodes,s),e=e&&!ms(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const _s=new Map;let ys=0;function vs(){const t=window.devicePixelRatio;t!==ys&&(ys=t,_s.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function Ms(t,e,i){const s=t.canvas,n=s&&ge(s);if(!n)return;const o=ct(((t,e)=>{const s=n.clientWidth;i(t,e),s<n.clientWidth&&i()}),window),a=new ResizeObserver((t=>{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||o(i,s)}));return a.observe(n),function(t,e){_s.size||window.addEventListener("resize",vs),_s.set(t,e)}(t,o),a}function ws(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){_s.delete(t),_s.size||window.removeEventListener("resize",vs)}(t)}function ks(t,e,i){const s=t.canvas,n=ct((e=>{null!==t.ctx&&i(function(t,e){const i=us[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t);return function(t,e,i){t&&t.addEventListener(e,i,gs)}(s,e,n),n}class Ss extends hs{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t[ds]={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",fs(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(fs(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e[ds])return!1;const i=e[ds].initial;["height","width"].forEach((t=>{const n=i[t];s(n)?e.removeAttribute(t):e.setAttribute(t,n)}));const n=i.style||{};return Object.keys(n).forEach((t=>{e.style[t]=n[t]})),e.width=e.width,delete e[ds],!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:xs,detach:bs,resize:Ms}[e]||ks;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:ws,detach:ws,resize:ws}[e]||ps)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return we(t,e,i,s)}isAttached(t){const e=t&&ge(t);return!(!e||!e.isConnected)}}function Ps(t){return!fe()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?cs:Ss}var Ds=Object.freeze({__proto__:null,BasePlatform:hs,BasicPlatform:cs,DomPlatform:Ss,_detectPlatform:Ps});const Cs="transparent",Os={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=Qt(t||Cs),n=s.valid&&Qt(e||Cs);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class As{constructor(t,e,i,s){const n=e[i];s=Pi([t.to,s,n,t.from]);const o=Pi([t.from,n,s]);this._active=!0,this._fn=t.fn||Os[t.type||typeof o],this._easing=fi[t.easing]||fi.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=Pi([t.to,e,s,t.from]),this._from=Pi([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e<i),!this._active)return this._target[s]=a,void this._notify(!0);e<0?this._target[s]=n:(r=e/i%2,r=o&&r>1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t<i.length;t++)i[t][e]()}}class Ts{constructor(t,e){this._chart=t,this._properties=new Map,this.configure(e)}configure(t){if(!o(t))return;const e=Object.keys(ue.animation),i=this._properties;Object.getOwnPropertyNames(t).forEach((s=>{const a=t[s];if(!o(a))return;const r={};for(const t of e)r[t]=a[t];(n(a.properties)&&a.properties||[s]).forEach((t=>{t!==s&&i.has(t)||i.set(t,r)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e<s.length;e++){const n=t[s[e]];n&&n.active()&&i.push(n.wait())}return Promise.all(i)}(t.options.$animations,i).then((()=>{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new As(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(bt.add(this._chart,i),!0):void 0}}function Ls(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function Es(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n<o;++n)i.push(s[n].index);return i}function Rs(t,e,i,s={}){const n=t.keys,o="single"===s.mode;let r,l,h,c;if(null===e)return;let d=!1;for(r=0,l=n.length;r<l;++r){if(h=+n[r],h===i){if(d=!0,s.all)continue;break}c=t.values[h],a(c)&&(o||0===e||F(e)===F(c))&&(e+=c)}return d||s.all?e:0}function Is(t,e){const i=t&&t.options.stacked;return i||void 0===i&&void 0!==e.stack}function zs(t,e,i){const s=t[e]||(t[e]={});return s[i]||(s[i]={})}function Fs(t,e,i,s){for(const n of e.getMatchingVisibleMetas(s).reverse()){const e=t[n.index];if(i&&e>0||!i&&e<0)return n.index}return null}function Vs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;t<d;++t){const i=e[t],{[l]:o,[h]:d}=i;u=(i._stacks||(i._stacks={}))[h]=zs(n,c,o),u[r]=d,u._top=Fs(u,a,!0,s.type),u._bottom=Fs(u,a,!1,s.type);(u._visualValues||(u._visualValues={}))[r]=d}}function Bs(t,e){const i=t.scales;return Object.keys(i).filter((t=>i[t].axis===e)).shift()}function Ws(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i],void 0!==e[s]._visualValues&&void 0!==e[s]._visualValues[i]&&delete e[s]._visualValues[i]}}}const Ns=t=>"reset"===t||"none"===t,Hs=(t,e)=>e?t:Object.assign({},t);class js{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=Is(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&Ws(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=l(i.xAxisID,Bs(t,"x")),o=e.yAxisID=l(i.yAxisID,Bs(t,"y")),a=e.rAxisID=l(i.rAxisID,Bs(t,"r")),r=e.indexAxis,h=e.iAxisID=s(r,n,o,a),c=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(h),e.vScale=this.getScaleForId(c)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&rt(this._data,this),t._stacked&&Ws(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(o(e)){const t=this._cachedMeta;this._data=function(t,e){const{iScale:i,vScale:s}=e,n="x"===i.axis?"x":"y",o="x"===s.axis?"x":"y",a=Object.keys(t),r=new Array(a.length);let l,h,c;for(l=0,h=a.length;l<h;++l)c=a[l],r[l]={[n]:c,[o]:t[c]};return r}(e,t)}else if(i!==e){if(i){rt(i,this);const t=this._cachedMeta;Ws(t),t._parsed=[]}e&&Object.isExtensible(e)&&at(e,this),this._syncList=[],this._data=e}}addElements(){const t=this._cachedMeta;this._dataCheck(),this.datasetElementType&&(t.dataset=new this.datasetElementType)}buildOrUpdateElements(t){const e=this._cachedMeta,i=this.getDataset();let s=!1;this._dataCheck();const n=e._stacked;e._stacked=Is(e.vScale,e),e.stack!==i.stack&&(s=!0,Ws(e),e.stack=i.stack),this._resyncElements(t),(s||n!==e._stacked)&&(Vs(this,e._parsed),e._stacked=Is(e.vScale,e))}configure(){const t=this.chart.config,e=t.datasetScopeKeys(this._type),i=t.getOptionScopes(this.getDataset(),e,!0);this.options=t.createResolver(i,this.getContext()),this._parsing=this.options.parsing,this._cachedDataOpts={}}parse(t,e){const{_cachedMeta:i,_data:s}=this,{iScale:a,_stacked:r}=i,l=a.axis;let h,c,d,u=0===t&&e===s.length||i._sorted,f=t>0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,d=s;else{d=n(s[t])?this.parseArrayData(i,s,t,e):o(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const a=()=>null===c[l]||f&&c[l]<f[l];for(h=0;h<e;++h)i._parsed[h+t]=c=d[h],u&&(a()&&(u=!1),f=c);i._sorted=u}r&&Vs(this,d)}parsePrimitiveData(t,e,i,s){const{iScale:n,vScale:o}=t,a=n.axis,r=o.axis,l=n.getLabels(),h=n===o,c=new Array(s);let d,u,f;for(d=0,u=s;d<u;++d)f=d+i,c[d]={[a]:h||n.parse(l[f],f),[r]:o.parse(e[f],f)};return c}parseArrayData(t,e,i,s){const{xScale:n,yScale:o}=t,a=new Array(s);let r,l,h,c;for(r=0,l=s;r<l;++r)h=r+i,c=e[h],a[r]={x:n.parse(c[0],h),y:o.parse(c[1],h)};return a}parseObjectData(t,e,i,s){const{xScale:n,yScale:o}=t,{xAxisKey:a="x",yAxisKey:r="y"}=this._parsing,l=new Array(s);let h,c,d,u;for(h=0,c=s;h<c;++h)d=h+i,u=e[d],l[h]={x:n.parse(M(u,a),d),y:o.parse(M(u,r),d)};return l}getParsed(t){return this._cachedMeta._parsed[t]}getDataElement(t){return this._cachedMeta.data[t]}applyStack(t,e,i){const s=this.chart,n=this._cachedMeta,o=e[t.axis];return Rs({keys:Es(s,!0),values:e._stacks[t.axis]._visualValues},o,n.index,{mode:i})}updateRangeFromParsed(t,e,i,s){const n=i[e.axis];let o=null===n?NaN:n;const a=s&&i._stacks[e.axis];s&&a&&(s.values=a,o=Rs(s,n,this._cachedMeta.index)),t.min=Math.min(t.min,o),t.max=Math.max(t.max,o)}getMinMax(t,e){const i=this._cachedMeta,s=i._parsed,n=i._sorted&&t===i.iScale,o=s.length,r=this._getOtherScale(t),l=((t,e,i)=>t&&!e.hidden&&e._stacked&&{keys:Es(i,!0),values:null})(e,i,this.chart),h={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:c,max:d}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(r);let u,f;function g(){f=s[u];const e=f[r.axis];return!a(f[t.axis])||c>e||d<e}for(u=0;u<o&&(g()||(this.updateRangeFromParsed(h,t,f,l),!n));++u);if(n)for(u=o-1;u>=0;--u)if(!g()){this.updateRangeFromParsed(h,t,f,l);break}return h}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s<n;++s)o=e[s][t.axis],a(o)&&i.push(o);return i}getMaxOverflow(){return!1}getLabelAndValue(t){const e=this._cachedMeta,i=e.iScale,s=e.vScale,n=this.getParsed(t);return{label:i?""+i.getLabelForValue(n[i.axis]):"",value:s?""+s.getLabelForValue(n[s.axis]):""}}_update(t){const e=this._cachedMeta;this.update(t||"default"),e._clip=function(t){let e,i,s,n;return o(t)?(e=t.top,i=t.right,s=t.bottom,n=t.left):e=i=s=n=t,{top:e,right:i,bottom:s,left:n,disabled:!1===t}}(l(this.options.clip,function(t,e,i){if(!1===i)return!1;const s=Ls(t,i),n=Ls(e,i);return{top:n.end,right:s.end,bottom:n.start,left:s.start}}(e.xScale,e.yScale,this.getMaxOverflow())))}update(t){}draw(){const t=this._ctx,e=this.chart,i=this._cachedMeta,s=i.data||[],n=e.chartArea,o=[],a=this._drawStart||0,r=this._drawCount||s.length-a,l=this.options.drawActiveElementsOnTop;let h;for(i.dataset&&i.dataset.draw(t,n,a,r),h=a;h<a+r;++h){const e=s[h];e.hidden||(e.active&&l?o.push(e):e.draw(t,n))}for(h=0;h<o.length;++h)o[h].draw(t,n)}getStyle(t,e){const i=e?"active":"default";return void 0===t&&this._cachedMeta.dataset?this.resolveDatasetElementOptions(i):this.resolveDataElementOptions(t||0,i)}getContext(t,e,i){const s=this.getDataset();let n;if(t>=0&&t<this._cachedMeta.data.length){const e=this._cachedMeta.data[t];n=e.$context||(e.$context=function(t,e,i){return Ci(t,{active:!1,dataIndex:e,parsed:void 0,raw:void 0,element:i,index:e,mode:"default",type:"data"})}(this.getContext(),t,e)),n.parsed=this.getParsed(t),n.raw=s.data[t],n.index=n.dataIndex=t}else n=this.$context||(this.$context=function(t,e){return Ci(t,{active:!1,dataset:void 0,datasetIndex:e,index:e,mode:"default",type:"dataset"})}(this.chart.getContext(),this.index)),n.dataset=s,n.index=n.datasetIndex=this.index;return n.active=!!e,n.mode=i,n}resolveDatasetElementOptions(t){return this._resolveElementOptions(this.datasetElementType.id,t)}resolveDataElementOptions(t,e){return this._resolveElementOptions(this.dataElementType.id,e,t)}_resolveElementOptions(t,e="default",i){const s="active"===e,n=this._cachedDataOpts,o=t+"-"+e,a=n[o],r=this.enableOptionSharing&&k(i);if(a)return Hs(a,r);const l=this.chart.config,h=l.datasetElementScopeKeys(this._type,t),c=s?[`${t}Hover`,"hover",t,""]:[t,""],d=l.getOptionScopes(this.getDataset(),h),u=Object.keys(ue.elements[t]),f=l.resolveNamedOptions(d,u,(()=>this.getContext(i,s,e)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Hs(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new Ts(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||Ns(t)||this.chart._animationsDisabled}_getSharedOptions(t,e){const i=this.resolveDataElementOptions(t,e),s=this._sharedOptions,n=this.getSharedOptions(i),o=this.includeOptions(e,n)||n!==s;return this.updateSharedOptions(n,e,i),{sharedOptions:n,includeOptions:o}}updateElement(t,e,i,s){Ns(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!Ns(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n<s&&this._removeElements(n,s-n)}_insertElements(t,e,i=!0){const s=this._cachedMeta,n=s.data,o=t+e;let a;const r=t=>{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a<o;++a)n[a]=new this.dataElementType;this._parsing&&r(s._parsed),this.parse(t,e),i&&this.updateElements(n,t,e,"reset")}updateElements(t,e,i,s){}_removeElements(t,e){const i=this._cachedMeta;if(this._parsing){const s=i._parsed.splice(t,e);i._stacked&&Ws(i,s)}i.data.splice(t,e)}_sync(t){if(this._parsing)this._syncList.push(t);else{const[e,i,s]=t;this[e](i,s)}this.chart._dataChanges.push([this.index,...t])}_onDataPush(){const t=arguments.length;this._sync(["_insertElements",this.getDataset().data.length-t,t])}_onDataPop(){this._sync(["_removeElements",this._cachedMeta.data.length-1,1])}_onDataShift(){this._sync(["_removeElements",0,1])}_onDataSplice(t,e){e&&this._sync(["_removeElements",t,e]);const i=arguments.length-2;i&&this._sync(["_insertElements",t,i])}_onDataUnshift(){this._sync(["_insertElements",0,arguments.length])}}class $s{static defaults={};static defaultRoutes=void 0;x;y;active=!1;options;$animations;tooltipPosition(t){const{x:e,y:i}=this.getProps(["x","y"],t);return{x:e,y:i}}hasValue(){return N(this.x)&&N(this.y)}getProps(t,e){const i=this.$animations;if(!e||!i)return this;const s={};return t.forEach((t=>{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}function Ys(t,e){const i=t.options.ticks,n=function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),o=Math.min(i.maxTicksLimit||n,n),a=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;i<s;i++)t[i].major&&e.push(i);return e}(e):[],r=a.length,l=a[0],h=a[r-1],c=[];if(r>o)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;n<t.length;n++)n===a&&(e.push(t[n]),o++,a=i[o*s])}(e,c,a,r/o),c;const d=function(t,e,i){const s=function(t){const e=t.length;let i,s;if(e<2)return!1;for(s=t[0],i=1;i<e;++i)if(t[i]-t[i-1]!==s)return!1;return s}(t),n=e.length/i;if(!s)return Math.max(n,1);const o=W(s);for(let t=0,e=o.length-1;t<e;t++){const e=o[t];if(e>n)return e}return Math.max(n,1)}(a,e,o);if(r>0){let t,i;const n=r>1?Math.round((h-l)/(r-1)):null;for(Us(e,c,d,s(n)?0:l-n,l),t=0,i=r-1;t<i;t++)Us(e,c,d,a[t],a[t+1]);return Us(e,c,d,h,s(n)?e.length:h+n),c}return Us(e,c,d),c}function Us(t,e,i,s,n){const o=l(s,0),a=Math.min(l(n,t.length),t.length);let r,h,c,d=0;for(i=Math.ceil(i),n&&(r=n-s,i=r/Math.floor(r/i)),c=o;c<0;)d++,c=Math.round(o+d*i);for(h=Math.max(o,0);h<a;h++)h===c&&(e.push(t[h]),d++,c=Math.round(o+d*i))}const Xs=(t,e,i)=>"top"===e||"left"===e?t[e]+i:t[e]-i,qs=(t,e)=>Math.min(e||t,t);function Ks(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;o<n;o+=s)i.push(t[Math.floor(o)]);return i}function Gs(t,e,i){const s=t.ticks.length,n=Math.min(e,s-1),o=t._startPixel,a=t._endPixel,r=1e-6;let l,h=t.getPixelForTick(n);if(!(i&&(l=1===s?Math.max(h-o,a-h):0===e?(t.getPixelForTick(1)-h)/2:(h-t.getPixelForTick(n-1))/2,h+=n<e?l:-l,h<o-r||h>a+r)))return h}function Js(t){return t.drawTicks?t.tickLength:0}function Zs(t,e){if(!t.display)return 0;const i=Si(t.font,e),s=ki(t.padding);return(n(t.text)?t.text.length:1)*i.lineHeight+s.height}function Qs(t,e,i){let s=ut(t);return(i&&"right"!==e||!i&&"right"===e)&&(s=(t=>"left"===t?"right":"right"===t?"left":t)(s)),s}class tn extends $s{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=r(t,Number.POSITIVE_INFINITY),e=r(e,Number.NEGATIVE_INFINITY),i=r(i,Number.POSITIVE_INFINITY),s=r(s,Number.NEGATIVE_INFINITY),{min:r(t,i),max:r(e,s),minDefined:a(t),maxDefined:a(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;r<l;++r)e=a[r].controller.getMinMax(this,t),n||(i=Math.min(i,e.min)),o||(s=Math.max(s,e.max));return i=o&&i>s?s:i,s=n&&i>s?i:s,{min:r(i,r(s,i)),max:r(s,r(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=Di(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a<this.ticks.length;this._convertTicksToLabels(r?Ks(this.ticks,a):this.ticks),this.configure(),this.beforeCalculateLabelRotation(),this.calculateLabelRotation(),this.afterCalculateLabelRotation(),o.display&&(o.autoSkip||"auto"===o.source)&&(this.ticks=Ys(this,this.ticks),this._labelSizes=null,this.afterAutoSkip()),r&&this._convertTicksToLabels(this.ticks),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate()}configure(){let t,e,i=this.options.reverse;this.isHorizontal()?(t=this.left,e=this.right):(t=this.top,e=this.bottom,i=!i),this._startPixel=t,this._endPixel=e,this._reversePixels=i,this._length=e-t,this._alignToPixels=this.options.alignToPixels}afterUpdate(){d(this.options.afterUpdate,[this])}beforeSetDimensions(){d(this.options.beforeSetDimensions,[this])}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0}afterSetDimensions(){d(this.options.afterSetDimensions,[this])}_callHooks(t){this.chart.notifyPlugins(t,this.getContext()),d(this.options[t],[this])}beforeDataLimits(){this._callHooks("beforeDataLimits")}determineDataLimits(){}afterDataLimits(){this._callHooks("afterDataLimits")}beforeBuildTicks(){this._callHooks("beforeBuildTicks")}buildTicks(){return[]}afterBuildTicks(){this._callHooks("afterBuildTicks")}beforeTickToLabelConversion(){d(this.options.beforeTickToLabelConversion,[this])}generateTickLabels(t){const e=this.options.ticks;let i,s,n;for(i=0,s=t.length;i<s;i++)n=t[i],n.label=d(e.callback,[n.value,i,t],this)}afterTickToLabelConversion(){d(this.options.afterTickToLabelConversion,[this])}beforeCalculateLabelRotation(){d(this.options.beforeCalculateLabelRotation,[this])}calculateLabelRotation(){const t=this.options,e=t.ticks,i=qs(this.ticks.length,t.ticks.maxTicksLimit),s=e.minRotation||0,n=e.maxRotation;let o,a,r,l=s;if(!this._isVisible()||!e.display||s>=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=Z(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Js(t.grid)-e.padding-Zs(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=Y(Math.min(Math.asin(Z((h.highest.height+6)/o,-1,1)),Math.asin(Z(a/r,-1,1))-Math.asin(Z(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){d(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){d(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=Zs(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Js(n)+o):(t.height=this.maxHeight,t.width=Js(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=$(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:"inner"!==n&&(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){d(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e<i;e++)s(t[e].label)&&(t.splice(e,1),i--,e--);this.afterTickToLabelConversion()}_getLabelSizes(){let t=this._labelSizes;if(!t){const e=this.options.ticks.sampleSize;let i=this.ticks;e<i.length&&(i=Ks(i,e)),this._labelSizes=t=this._computeLabelSizes(i,i.length,this.options.ticks.maxTicksLimit)}return t}_computeLabelSizes(t,e,i){const{ctx:o,_longestTextCache:a}=this,r=[],l=[],h=Math.floor(e/qs(e,i));let c,d,f,g,p,m,x,b,_,y,v,M=0,w=0;for(c=0;c<e;c+=h){if(g=t[c].label,p=this._resolveTickFontOptions(c),o.font=m=p.string,x=a[m]=a[m]||{data:{},gc:[]},b=p.lineHeight,_=y=0,s(g)||n(g)){if(n(g))for(d=0,f=g.length;d<f;++d)v=g[d],s(v)||n(v)||(_=Ce(o,x.data,x.gc,_,v),y+=b)}else _=Ce(o,x.data,x.gc,_,g),y=b;r.push(_),l.push(y),M=Math.max(_,M),w=Math.max(y,w)}!function(t,e){u(t,(t=>{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n<s;++n)delete t.data[i[n]];i.splice(0,s)}}))}(a,e);const k=r.indexOf(M),S=l.indexOf(w),P=t=>({width:r[t]||0,height:l[t]||0});return{first:P(0),last:P(e-1),widest:P(k),highest:P(S),widths:r,heights:l}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return Q(this._alignToPixels?Ae(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&t<e.length){const i=e[t];return i.$context||(i.$context=function(t,e,i){return Ci(t,{tick:i,index:e,type:"tick"})}(this.getContext(),t,i))}return this.$context||(this.$context=Ci(this.chart.getContext(),{scale:this,type:"scale"}))}_tickSize(){const t=this.options.ticks,e=$(this.labelRotation),i=Math.abs(Math.cos(e)),s=Math.abs(Math.sin(e)),n=this._getLabelSizes(),o=t.autoSkipPadding||0,a=n?n.widest.width+o:0,r=n?n.highest.height+o:0;return this.isHorizontal()?r*i>a*s?a/i:r/s:r*s<a*i?r/i:a/s}_isVisible(){const t=this.options.display;return"auto"!==t?!!t:this.getMatchingVisibleMetas().length>0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:a,border:r}=s,h=n.offset,c=this.isHorizontal(),d=this.ticks.length+(h?1:0),u=Js(n),f=[],g=r.setContext(this.getContext()),p=g.display?g.width:0,m=p/2,x=function(t){return Ae(i,t,p)};let b,_,y,v,M,w,k,S,P,D,C,O;if("top"===a)b=x(this.bottom),w=this.bottom-u,S=b-m,D=x(t.top)+m,O=t.bottom;else if("bottom"===a)b=x(this.top),D=t.top,O=x(t.bottom)-m,w=b+m,S=this.top+u;else if("left"===a)b=x(this.right),M=this.right-u,k=b-m,P=x(t.left)+m,C=t.right;else if("right"===a)b=x(this.left),P=t.left,C=x(t.right)-m,M=b+m,k=this.left+u;else if("x"===e){if("center"===a)b=x((t.top+t.bottom)/2+.5);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}D=t.top,O=t.bottom,w=b+m,S=w+u}else if("y"===e){if("center"===a)b=x((t.left+t.right)/2);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}M=b-m,k=M-u,P=t.left,C=t.right}const A=l(s.ticks.maxTicksLimit,d),T=Math.max(1,Math.ceil(d/A));for(_=0;_<d;_+=T){const t=this.getContext(_),e=n.setContext(t),s=r.setContext(t),o=e.lineWidth,a=e.color,l=s.dash||[],d=s.dashOffset,u=e.tickWidth,g=e.tickColor,p=e.tickBorderDash||[],m=e.tickBorderDashOffset;y=Gs(this,_,h),void 0!==y&&(v=Ae(i,y,o),c?M=k=P=C=v:w=S=D=O=v,f.push({tx1:M,ty1:w,tx2:k,ty2:S,x1:P,y1:D,x2:C,y2:O,width:o,color:a,borderDash:l,borderDashOffset:d,tickWidth:u,tickColor:g,tickBorderDash:p,tickBorderDashOffset:m}))}return this._ticksLength=d,this._borderValue=b,f}_computeLabelItems(t){const e=this.axis,i=this.options,{position:s,ticks:a}=i,r=this.isHorizontal(),l=this.ticks,{align:h,crossAlign:c,padding:d,mirror:u}=a,f=Js(i.grid),g=f+d,p=u?-d:g,m=-$(this.labelRotation),x=[];let b,_,y,v,M,w,k,S,P,D,C,O,A="middle";if("top"===s)w=this.bottom-p,k=this._getXAxisLabelAlignment();else if("bottom"===s)w=this.top+p,k=this._getXAxisLabelAlignment();else if("left"===s){const t=this._getYAxisLabelAlignment(f);k=t.textAlign,M=t.x}else if("right"===s){const t=this._getYAxisLabelAlignment(f);k=t.textAlign,M=t.x}else if("x"===e){if("center"===s)w=(t.top+t.bottom)/2+g;else if(o(s)){const t=Object.keys(s)[0],e=s[t];w=this.chart.scales[t].getPixelForValue(e)+g}k=this._getXAxisLabelAlignment()}else if("y"===e){if("center"===s)M=(t.left+t.right)/2-g;else if(o(s)){const t=Object.keys(s)[0],e=s[t];M=this.chart.scales[t].getPixelForValue(e)}k=this._getYAxisLabelAlignment(f).textAlign}"y"===e&&("start"===h?A="top":"end"===h&&(A="bottom"));const T=this._getLabelSizes();for(b=0,_=l.length;b<_;++b){y=l[b],v=y.label;const t=a.setContext(this.getContext(b));S=this.getPixelForTick(b)+a.labelOffset,P=this._resolveTickFontOptions(b),D=P.lineHeight,C=n(v)?v.length:1;const e=C/2,i=t.color,o=t.textStrokeColor,h=t.textStrokeWidth;let d,f=k;if(r?(M=S,"inner"===k&&(f=b===_-1?this.options.reverse?"left":"right":0===b?this.options.reverse?"right":"left":"center"),O="top"===s?"near"===c||0!==m?-C*D+D/2:"center"===c?-T.highest.height/2-e*D+D:-T.highest.height+D/2:"near"===c||0!==m?D/2:"center"===c?T.highest.height/2-e*D:T.highest.height-C*D,u&&(O*=-1),0===m||t.showLabelBackdrop||(M+=D/2*Math.sin(m))):(w=S,O=(1-C)*D/2),t.showLabelBackdrop){const e=ki(t.backdropPadding),i=T.heights[b],s=T.widths[b];let n=O-e.top,o=0-e.left;switch(A){case"middle":n-=i/2;break;case"bottom":n-=i}switch(k){case"center":o-=s/2;break;case"right":o-=s;break;case"inner":b===_-1?o-=s:b>0&&(o-=s/2)}d={left:o,top:n,width:s+e.width,height:i+e.height,color:t.backdropColor}}x.push({label:v,font:P,textOffset:O,options:{rotation:m,color:i,strokeColor:o,strokeWidth:h,textAlign:f,textBaseline:A,translation:[M,w],backdrop:d}})}return x}_getXAxisLabelAlignment(){const{position:t,ticks:e}=this.options;if(-$(this.labelRotation))return"top"===t?"left":"right";let i="center";return"start"===e.align?i="left":"end"===e.align?i="right":"inner"===e.align&&(i="inner"),i}_getYAxisLabelAlignment(t){const{position:e,ticks:{crossAlign:i,mirror:s,padding:n}}=this.options,o=t+n,a=this._getLabelSizes().widest.width;let r,l;return"left"===e?s?(l=this.right+n,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l+=a)):(l=this.right-o,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l=this.left)):"right"===e?s?(l=this.left+n,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l-=a)):(l=this.left+o,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l=this.right)):r="right",{textAlign:r,x:l}}_computeLabelArea(){if(this.options.ticks.mirror)return;const t=this.chart,e=this.options.position;return"left"===e||"right"===e?{top:0,left:this.left,bottom:t.height,right:this.right}:"top"===e||"bottom"===e?{top:this.top,left:0,bottom:this.bottom,right:t.width}:void 0}drawBackground(){const{ctx:t,options:{backgroundColor:e},left:i,top:s,width:n,height:o}=this;e&&(t.save(),t.fillStyle=e,t.fillRect(i,s,n,o),t.restore())}getLineWidthForValue(t){const e=this.options.grid;if(!this._isVisible()||!e.display)return 0;const i=this.ticks.findIndex((e=>e.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n<o;++n){const t=s[n];e.drawOnChartArea&&a({x:t.x1,y:t.y1},{x:t.x2,y:t.y2},t),e.drawTicks&&a({x:t.tx1,y:t.ty1},{x:t.tx2,y:t.ty2},{color:t.tickColor,width:t.tickWidth,borderDash:t.tickBorderDash,borderDashOffset:t.tickBorderDashOffset})}}drawBorder(){const{chart:t,ctx:e,options:{border:i,grid:s}}=this,n=i.setContext(this.getContext()),o=i.display?n.width:0;if(!o)return;const a=s.setContext(this.getContext(0)).lineWidth,r=this._borderValue;let l,h,c,d;this.isHorizontal()?(l=Ae(t,this.left,o)-o/2,h=Ae(t,this.right,a)+a/2,c=d=r):(c=Ae(t,this.top,o)-o/2,d=Ae(t,this.bottom,a)+a/2,l=h=r),e.save(),e.lineWidth=n.width,e.strokeStyle=n.color,e.beginPath(),e.moveTo(l,c),e.lineTo(h,d),e.stroke(),e.restore()}drawLabels(t){if(!this.options.ticks.display)return;const e=this.ctx,i=this._computeLabelArea();i&&Ie(e,i);const s=this.getLabelItems(t);for(const t of s){const i=t.options,s=t.font;Ne(e,t.label,0,t.textOffset,s,i)}i&&ze(e)}drawTitle(){const{ctx:t,options:{position:e,title:i,reverse:s}}=this;if(!i.display)return;const a=Si(i.font),r=ki(i.padding),l=i.align;let h=a.lineHeight/2;"bottom"===e||"center"===e||o(e)?(h+=r.bottom,n(i.text)&&(h+=a.lineHeight*(i.text.length-1))):h+=r.top;const{titleX:c,titleY:d,maxWidth:u,rotation:f}=function(t,e,i,s){const{top:n,left:a,bottom:r,right:l,chart:h}=t,{chartArea:c,scales:d}=h;let u,f,g,p=0;const m=r-n,x=l-a;if(t.isHorizontal()){if(f=ft(s,a,l),o(i)){const t=Object.keys(i)[0],s=i[t];g=d[t].getPixelForValue(s)+m-e}else g="center"===i?(c.bottom+c.top)/2+m-e:Xs(t,i,e);u=l-a}else{if(o(i)){const t=Object.keys(i)[0],s=i[t];f=d[t].getPixelForValue(s)-x+e}else f="center"===i?(c.left+c.right)/2-x+e:Xs(t,i,e);g=ft(s,r,n),p="left"===i?-E:E}return{titleX:f,titleY:g,maxWidth:u,rotation:p}}(this,h,e,l);Ne(t,i.text,0,0,a,{color:i.color,maxWidth:u,rotation:f,textAlign:Qs(l,e,s),textBaseline:"middle",translation:[c,d]})}draw(t){this._isVisible()&&(this.drawBackground(),this.drawGrid(t),this.drawBorder(),this.drawTitle(),this.drawLabels(t))}_layers(){const t=this.options,e=t.ticks&&t.ticks.z||0,i=l(t.grid&&t.grid.z,-1),s=l(t.border&&t.border.z,0);return this._isVisible()&&this.draw===tn.prototype.draw?[{z:i,draw:t=>{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:s,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n<o;++n){const o=e[n];o[i]!==this.id||t&&o.type!==t||s.push(o)}return s}_resolveTickFontOptions(t){return Si(this.options.ticks.setContext(this.getContext(t)).font)}_maxDigits(){const t=this._resolveTickFontOptions(0).lineHeight;return(this.isHorizontal()?this.width:this.height)/t}}class en{constructor(t,e,i){this.type=t,this.scope=e,this.override=i,this.items=Object.create(null)}isForType(t){return Object.prototype.isPrototypeOf.call(this.type.prototype,t.prototype)}register(t){const e=Object.getPrototypeOf(t);let i;(function(t){return"id"in t&&"defaults"in t})(e)&&(i=this.register(e));const s=this.items,n=t.id,o=this.scope+"."+n;if(!n)throw new Error("class does not have id: "+t);return n in s||(s[n]=t,function(t,e,i){const s=x(Object.create(null),[i?ue.get(i):{},ue.get(e),t.defaults]);ue.set(e,s),t.defaultRoutes&&function(t,e){Object.keys(e).forEach((i=>{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");ue.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&ue.describe(e,t.descriptors)}(t,o,i),this.override&&ue.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in ue[s]&&(delete ue[s][i],this.override&&delete re[i])}}class sn{constructor(){this.controllers=new en(js,"datasets",!0),this.elements=new en($s,"elements"),this.plugins=new en(Object,"plugins"),this.scales=new en(tn,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):u(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=w(t);d(i["before"+s],[],i),e[t](i),d(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;e<this._typedRegistries.length;e++){const i=this._typedRegistries[e];if(i.isForType(t))return i}return this.plugins}_get(t,e,i){const s=e.get(t);if(void 0===s)throw new Error('"'+t+'" is not a registered '+i+".");return s}}var nn=new sn;class on{constructor(){this._init=void 0}notify(t,e,i,s){if("beforeInit"===e&&(this._init=this._createDescriptors(t,!0),this._notify(this._init,t,"install")),void 0===this._init)return;const n=s?this._descriptors(t).filter(s):this._descriptors(t),o=this._notify(n,t,e,i);return"afterDestroy"===e&&(this._notify(n,t,"stop"),this._notify(this._init,t,"uninstall"),this._init=void 0),o}_notify(t,e,i,s){s=s||{};for(const n of t){const t=n.plugin;if(!1===d(t[i],[e,s,n.options],t)&&s.cancelable)return!1}return!0}invalidate(){s(this._cache)||(this._oldCache=this._cache,this._cache=void 0)}_descriptors(t){if(this._cache)return this._cache;const e=this._cache=this._createDescriptors(t);return this._notifyStateChanges(t),e}_createDescriptors(t,e){const i=t&&t.config,s=l(i.options&&i.options.plugins,{}),n=function(t){const e={},i=[],s=Object.keys(nn.plugins.items);for(let t=0;t<s.length;t++)i.push(nn.getPlugin(s[t]));const n=t.plugins||[];for(let t=0;t<n.length;t++){const s=n[t];-1===i.indexOf(s)&&(i.push(s),e[s.id]=!0)}return{plugins:i,localIds:e}}(i);return!1!==s||e?function(t,{plugins:e,localIds:i},s,n){const o=[],a=t.getContext();for(const r of e){const e=r.id,l=an(s[e],n);null!==l&&o.push({plugin:r,options:rn(t.config,{plugin:r,local:i[e]},l,a)})}return o}(t,n,s,e):[]}_notifyStateChanges(t){const e=this._oldCache||[],i=this._cache,s=(t,e)=>t.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function an(t,e){return e||!1!==t?!0===t?{}:t:null}function rn(t,{plugin:e,local:i},s,n){const o=t.pluginScopeKeys(e),a=t.getOptionScopes(s,o);return i&&e.defaults&&a.push(e.defaults),t.createResolver(a,n,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function ln(t,e){const i=ue.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function hn(t){if("x"===t||"y"===t||"r"===t)return t}function cn(t,...e){if(hn(t))return t;for(const s of e){const e=s.axis||("top"===(i=s.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.length>1&&hn(t[0].toLowerCase());if(e)return e}var i;throw new Error(`Cannot determine type of '${t}' axis. Please provide 'axis' or 'position' option.`)}function dn(t,e,i){if(i[e+"AxisID"]===t)return{axis:e}}function un(t,e){const i=re[t.type]||{scales:{}},s=e.scales||{},n=ln(t.type,e),a=Object.create(null);return Object.keys(s).forEach((e=>{const r=s[e];if(!o(r))return console.error(`Invalid scale configuration for scale: ${e}`);if(r._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${e}`);const l=cn(e,r,function(t,e){if(e.data&&e.data.datasets){const i=e.data.datasets.filter((e=>e.xAxisID===t||e.yAxisID===t));if(i.length)return dn(t,"x",i[0])||dn(t,"y",i[0])}return{}}(e,t),ue.scales[r.type]),h=function(t,e){return t===e?"_index_":"_value_"}(l,n),c=i.scales||{};a[e]=b(Object.create(null),[{axis:l},r,c[l],c[h]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,o=i.indexAxis||ln(n,e),r=(re[n]||{}).scales||{};Object.keys(r).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,o),n=i[e+"AxisID"]||e;a[n]=a[n]||Object.create(null),b(a[n],[{axis:e},s[n],r[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];b(e,[ue.scales[e.type],ue.scale])})),a}function fn(t){const e=t.options||(t.options={});e.plugins=l(e.plugins,{}),e.scales=un(t,e)}function gn(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const pn=new Map,mn=new Set;function xn(t,e){let i=pn.get(t);return i||(i=e(),pn.set(t,i),mn.add(i)),i}const bn=(t,e,i)=>{const s=M(e,i);void 0!==s&&t.add(s)};class _n{constructor(t){this._config=function(t){return(t=t||{}).data=gn(t.data),fn(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=gn(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),fn(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return xn(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return xn(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return xn(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return xn(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>bn(r,t,e)))),e.forEach((t=>bn(r,s,t))),e.forEach((t=>bn(r,re[n]||{},t))),e.forEach((t=>bn(r,ue,t))),e.forEach((t=>bn(r,le,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),mn.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,re[e]||{},ue.datasets[e]||{},{type:e},ue,le]}resolveNamedOptions(t,e,i,s=[""]){const o={$shared:!0},{resolver:a,subPrefixes:r}=yn(this._resolverCache,t,s);let l=a;if(function(t,e){const{isScriptable:i,isIndexable:s}=Ye(t);for(const o of e){const e=i(o),a=s(o),r=(a||e)&&t[o];if(e&&(S(r)||vn(r))||a&&n(r))return!0}return!1}(a,e)){o.$shared=!1;l=$e(a,i=S(i)?i():i,this.createResolver(t,i,r))}for(const t of e)o[t]=l[t];return o}createResolver(t,e,i=[""],s){const{resolver:n}=yn(this._resolverCache,t,i);return o(e)?$e(n,e,void 0,s):n}}function yn(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:je(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const vn=t=>o(t)&&Object.getOwnPropertyNames(t).some((e=>S(t[e])));const Mn=["top","bottom","left","right","chartArea"];function wn(t,e){return"top"===t||"bottom"===t||-1===Mn.indexOf(t)&&"x"===e}function kn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function Sn(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),d(i&&i.onComplete,[t],e)}function Pn(t){const e=t.chart,i=e.options.animation;d(i&&i.onProgress,[t],e)}function Dn(t){return fe()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const Cn={},On=t=>{const e=Dn(t);return Object.values(Cn).filter((t=>t.canvas===e)).pop()};function An(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}class Tn{static defaults=ue;static instances=Cn;static overrides=re;static registry=nn;static version="4.5.1";static getChart=On;static register(...t){nn.add(...t),Ln()}static unregister(...t){nn.remove(...t),Ln()}constructor(t,e){const s=this.config=new _n(e),n=Dn(t),o=On(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas with ID '"+o.canvas.id+"' can be reused.");const a=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||Ps(n)),this.platform.updateConfig(s);const r=this.platform.acquireContext(n,a.aspectRatio),l=r&&r.canvas,h=l&&l.height,c=l&&l.width;this.id=i(),this.ctx=r,this.canvas=l,this.width=c,this.height=h,this._options=a,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new on,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=dt((t=>this.update(t)),a.resizeDelay||0),this._dataChanges=[],Cn[this.id]=this,r&&l?(bt.listen(this,"complete",Sn),bt.listen(this,"progress",Pn),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:n,_aspectRatio:o}=this;return s(t)?e&&o?o:n?i/n:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return nn}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Te(this.canvas,this.ctx),this}stop(){return bt.stop(this),this}resize(t,e){bt.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),d(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){u(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=cn(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),u(n,(e=>{const n=e.options,o=n.id,a=cn(o,n),r=l(n.type,e.dtype);void 0!==n.position&&wn(n.position,a)===wn(e.dposition)||(n.position=e.dposition),s[o]=!0;let h=null;if(o in i&&i[o].type===r)h=i[o];else{h=new(nn.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[h.id]=h}h.init(n,t)})),u(s,((t,e)=>{t||delete i[e]})),u(i,(t=>{ls.configure(this,t,t.options),ls.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;t<i;++t)this._destroyDatasetMeta(t);t.splice(e,i-e)}this._sortedMetasets=t.slice(0).sort(kn("order","index"))}_removeUnreferencedMetasets(){const{_metasets:t,data:{datasets:e}}=this;t.length>e.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i<s;i++){const s=e[i];let n=this.getDatasetMeta(i);const o=s.type||this.config.type;if(n.type&&n.type!==o&&(this._destroyDatasetMeta(i),n=this.getDatasetMeta(i)),n.type=o,n.indexAxis=s.indexAxis||ln(o,this.options),n.order=s.order||0,n.index=i,n.label=""+s.label,n.visible=this.isDatasetVisible(i),n.controller)n.controller.updateIndex(i),n.controller.linkScales();else{const e=nn.getController(o),{datasetElementType:s,dataElementType:a}=ue.datasets[o];Object.assign(e,{dataElementType:nn.getElement(a),datasetElementType:s&&nn.getElement(s)}),n.controller=new e(this,i),t.push(n.controller)}}return this._updateMetasets(),t}_resetElements(){u(this.data.datasets,((t,e)=>{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t<e;t++){const{controller:e}=this.getDatasetMeta(t),i=!s&&-1===n.indexOf(e);e.buildOrUpdateElements(i),o=Math.max(+e.getMaxOverflow(),o)}o=this._minPadding=i.layout.autoPadding?o:0,this._updateLayout(o),s||u(n,(t=>{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(kn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){u(this.scales,(t=>{ls.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);P(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){An(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;t<e;t++)if(!P(s,i(t)))return;return Array.from(s).map((t=>t.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ls.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],u(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t<e;++t)this.getDatasetMeta(t).controller.configure();for(let e=0,i=this.data.datasets.length;e<i;++e)this._updateDataset(e,S(t)?t({datasetIndex:e}):t);this.notifyPlugins("afterDatasetsUpdate",{mode:t})}}_updateDataset(t,e){const i=this.getDatasetMeta(t),s={meta:i,index:t,mode:e,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetUpdate",s)&&(i.controller._update(e),s.cancelable=!1,this.notifyPlugins("afterDatasetUpdate",s))}render(){!1!==this.notifyPlugins("beforeRender",{cancelable:!0})&&(bt.has(this)?this.attached&&!bt.running(this)&&bt.start(this):(this.draw(),Sn({chart:this})))}draw(){let t;if(this._resizeBeforeDraw){const{width:t,height:e}=this._resizeBeforeDraw;this._resizeBeforeDraw=null,this._resize(t,e)}if(this.clear(),this.width<=0||this.height<=0)return;if(!1===this.notifyPlugins("beforeDraw",{cancelable:!0}))return;const e=this._layers;for(t=0;t<e.length&&e[t].z<=0;++t)e[t].draw(this.chartArea);for(this._drawDatasets();t<e.length;++t)e[t].draw(this.chartArea);this.notifyPlugins("afterDraw")}_getSortedDatasetMetas(t){const e=this._sortedMetasets,i=[];let s,n;for(s=0,n=e.length;s<n;++s){const n=e[s];t&&!n.visible||i.push(n)}return i}getSortedVisibleDatasetMetas(){return this._getSortedDatasetMetas(!0)}_drawDatasets(){if(!1===this.notifyPlugins("beforeDatasetsDraw",{cancelable:!0}))return;const t=this.getSortedVisibleDatasetMetas();for(let e=t.length-1;e>=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i={meta:t,index:t.index,cancelable:!0},s=Ni(this,t);!1!==this.notifyPlugins("beforeDatasetDraw",i)&&(s&&Ie(e,s),t.controller.draw(),s&&ze(e),i.cancelable=!1,this.notifyPlugins("afterDatasetDraw",i))}isPointInArea(t){return Re(t,this.chartArea,this._minPadding)}getElementsAtEventForMode(t,e,i,s){const n=Ki.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ci(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);k(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),bt.remove(this),t=0,e=this.data.datasets.length;t<e;++t)this._destroyDatasetMeta(t)}destroy(){this.notifyPlugins("beforeDestroy");const{canvas:t,ctx:e}=this;this._stop(),this.config.clearCache(),t&&(this.unbindEvents(),Te(t,e),this.platform.releaseContext(e),this.canvas=null,this.ctx=null),delete Cn[this.id],this.notifyPlugins("afterDestroy")}toBase64Image(...t){return this.canvas.toDataURL(...t)}bindEvents(){this.bindUserEvents(),this.options.responsive?this.bindResponsiveEvents():this.attached=!0}bindUserEvents(){const t=this._listeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};u(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){u(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},u(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a<r;++a){o=t[a];const e=o&&this.getDatasetMeta(o.datasetIndex).controller;e&&e[s+"HoverStyle"](o.element,o.datasetIndex,o.index)}}getActiveElements(){return this._active||[]}setActiveElements(t){const e=this._active||[],i=t.map((({datasetIndex:t,index:e})=>{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!f(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}isPluginEnabled(t){return 1===this._plugins._cache.filter((e=>e.plugin.id===t)).length}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:this.isPointInArea(t)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=D(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,d(n.onHover,[t,a,this],this),r&&d(n.onClick,[t,a,this],this));const h=!f(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}function Ln(){return u(Tn.instances,(t=>t._plugins.invalidate()))}function En(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class Rn{static override(t){Object.assign(Rn.prototype,t)}options;constructor(t){this.options=t||{}}init(){}formats(){return En()}parse(){return En()}format(){return En()}add(){return En()}diff(){return En()}startOf(){return En()}endOf(){return En()}}var In={_date:Rn};function zn(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;e<n;e++)s=s.concat(i[e].controller.getAllParsedValues(t));t._cache.$bar=lt(s.sort(((t,e)=>t-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(k(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;s<n;++s)o=e.getPixelForValue(i[s]),l();for(a=void 0,s=0,n=e.ticks.length;s<n;++s)o=e.getPixelForTick(s),l();return r}function Fn(t,e,i,s){return n(t)?function(t,e,i,s){const n=i.parse(t[0],s),o=i.parse(t[1],s),a=Math.min(n,o),r=Math.max(n,o);let l=a,h=r;Math.abs(a)>Math.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function Vn(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;h<c;++h)u=e[h],d={},d[n.axis]=r||n.parse(a[h],h),l.push(Fn(u,d,o,h));return l}function Bn(t){return t&&void 0!==t.barStart&&void 0!==t.barEnd}function Wn(t,e,i,s){let n=e.borderSkipped;const o={};if(!n)return void(t.borderSkipped=o);if(!0===n)return void(t.borderSkipped={top:!0,right:!0,bottom:!0,left:!0});const{start:a,end:r,reverse:l,top:h,bottom:c}=function(t){let e,i,s,n,o;return t.horizontal?(e=t.base>t.x,i="left",s="right"):(e=t.base<t.y,i="bottom",s="top"),e?(n="end",o="start"):(n="start",o="end"),{start:i,end:s,reverse:e,top:n,bottom:o}}(t);"middle"===n&&i&&(t.enableBorderRadius=!0,(i._top||0)===s?n=h:(i._bottom||0)===s?n=c:(o[Nn(c,a,r,l)]=!0,n=h)),o[Nn(n,a,r,l)]=!0,t.borderSkipped=o}function Nn(t,e,i,s){var n,o,a;return s?(a=i,t=Hn(t=(n=t)===(o=e)?a:n===a?o:n,i,e)):t=Hn(t,e,i),t}function Hn(t,e,i){return"start"===t?e:"end"===t?i:t}function jn(t,{inflateAmount:e},i){t.inflateAmount="auto"===e?1===i?.33:0:e}class $n extends js{static id="doughnut";static defaults={datasetElementType:!1,dataElementType:"arc",animation:{animateRotate:!0,animateScale:!1},animations:{numbers:{type:"number",properties:["circumference","endAngle","innerRadius","outerRadius","startAngle","x","y","offset","borderWidth","spacing"]}},cutout:"50%",rotation:0,circumference:360,radius:"100%",spacing:0,indexAxis:"r"};static descriptors={_scriptable:t=>"spacing"!==t,_indexable:t=>"spacing"!==t&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data,{labels:{pointStyle:i,textAlign:s,color:n,useBorderRadius:o,borderRadius:a}}=t.legend.options;return e.labels.length&&e.datasets.length?e.labels.map(((e,r)=>{const l=t.getDatasetMeta(0).controller.getStyle(r);return{text:e,fillStyle:l.backgroundColor,fontColor:n,hidden:!t.getDataVisibility(r),lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:l.borderWidth,strokeStyle:l.borderColor,textAlign:s,pointStyle:i,borderRadius:o&&(a||l.borderRadius),index:r}})):[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}}};constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,a,r=t=>+i[t];if(o(i[t])){const{key:t="value"}=this._parsing;r=e=>+M(i[e],t)}for(n=t,a=t+e;n<a;++n)s._parsed[n]=r(n)}}_getRotation(){return $(this.options.rotation-90)}_getCircumference(){return $(this.options.circumference)}_getRotationExtents(){let t=O,e=-O;for(let i=0;i<this.chart.data.datasets.length;++i)if(this.chart.isDatasetVisible(i)&&this.chart.getDatasetMeta(i).type===this._type){const s=this.chart.getDatasetMeta(i).controller,n=s._getRotation(),o=s._getCircumference();t=Math.min(t,n),e=Math.max(e,n+o)}return{rotation:t,circumference:e-t}}update(t){const e=this.chart,{chartArea:i}=e,s=this._cachedMeta,n=s.data,o=this.getMaxBorderWidth()+this.getMaxOffset(n)+this.options.spacing,a=Math.max((Math.min(i.width,i.height)-o)/2,0),r=Math.min(h(this.options.cutout,a),1),l=this._getRingWeight(this.index),{circumference:d,rotation:u}=this._getRotationExtents(),{ratioX:f,ratioY:g,offsetX:p,offsetY:m}=function(t,e,i){let s=1,n=1,o=0,a=0;if(e<O){const r=t,l=r+e,h=Math.cos(r),c=Math.sin(r),d=Math.cos(l),u=Math.sin(l),f=(t,e,s)=>J(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>J(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(E,c,u),x=g(C,h,d),b=g(C+E,c,u);s=(p-x)/2,n=(m-b)/2,o=-(p+x)/2,a=-(m+b)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(u,d,r),x=(i.width-o)/f,b=(i.height-o)/g,_=Math.max(Math.min(x,b)/2,0),y=c(this.options.radius,_),v=(y-Math.max(y*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=p*y,this.offsetY=m*y,s.total=this.calculateTotal(),this.outerRadius=y-v*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-v*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/O)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,{sharedOptions:f,includeOptions:g}=this._getSharedOptions(e,s);let p,m=this._getRotation();for(p=0;p<e;++p)m+=this._circumference(p,n);for(p=e;p<e+i;++p){const e=this._circumference(p,n),i=t[p],o={x:l+this.offsetX,y:h+this.offsetY,startAngle:m,endAngle:m+e,circumference:e,outerRadius:u,innerRadius:d};g&&(o.options=f||this.resolveDataElementOptions(p,i.active?"active":s)),m+=e,this.updateElement(i,p,o,s)}}calculateTotal(){const t=this._cachedMeta,e=t.data;let i,s=0;for(i=0;i<e.length;i++){const n=t._parsed[i];null===n||isNaN(n)||!this.chart.getDataVisibility(i)||e[i].hidden||(s+=Math.abs(n))}return s}calculateCircumference(t){const e=this._cachedMeta.total;return e>0&&!isNaN(t)?O*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s<n;++s)if(i.isDatasetVisible(s)){o=i.getDatasetMeta(s),t=o.data,a=o.controller;break}if(!t)return 0;for(s=0,n=t.length;s<n;++s)r=a.resolveDataElementOptions(s),"inner"!==r.borderAlign&&(e=Math.max(e,r.borderWidth||0,r.hoverBorderWidth||0));return e}getMaxOffset(t){let e=0;for(let i=0,s=t.length;i<s;++i){const t=this.resolveDataElementOptions(i);e=Math.max(e,t.offset||0,t.hoverOffset||0)}return e}_getRingWeightOffset(t){let e=0;for(let i=0;i<t;++i)this.chart.isDatasetVisible(i)&&(e+=this._getRingWeight(i));return e}_getRingWeight(t){return Math.max(l(this.chart.data.datasets[t].weight,1),0)}_getVisibleDatasetWeightTotal(){return this._getRingWeightOffset(this.chart.data.datasets.length)||1}}class Yn extends js{static id="polarArea";static defaults={dataElementType:"arc",animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:"number",properties:["x","y","startAngle","endAngle","innerRadius","outerRadius"]}},indexAxis:"r",startAngle:0};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i,color:s}}=t.legend.options;return e.labels.map(((e,n)=>{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}getMinMax(){const t=this._cachedMeta,e={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach(((t,i)=>{const s=this.getParsed(i).r;!isNaN(s)&&this.chart.getDataVisibility(i)&&(s<e.min&&(e.min=s),s>e.max&&(e.max=s))})),e}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.options.animation,r=this._cachedMeta.rScale,l=r.xCenter,h=r.yCenter,c=r.getIndexAngle(0)-.5*C;let d,u=c;const f=360/this.countVisibleElements();for(d=0;d<e;++d)u+=this._computeAngle(d,s,f);for(d=e;d<e+i;d++){const e=t[d];let i=u,g=u+this._computeAngle(d,s,f),p=o.getDataVisibility(d)?r.getDistanceFromCenterForValue(this.getParsed(d).r):0;u=g,n&&(a.animateScale&&(p=0),a.animateRotate&&(i=g=c));const m={x:l,y:h,innerRadius:0,outerRadius:p,startAngle:i,endAngle:g,options:this.resolveDataElementOptions(d,e.active?"active":s)};this.updateElement(e,d,m,s)}}countVisibleElements(){const t=this._cachedMeta;let e=0;return t.data.forEach(((t,i)=>{!isNaN(this.getParsed(i).r)&&this.chart.getDataVisibility(i)&&e++})),e}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?$(this.resolveDataElementOptions(t,e).angle||i):0}}var Un=Object.freeze({__proto__:null,BarController:class extends js{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(t,e,i,s){return Vn(t,e,i,s)}parseArrayData(t,e,i,s){return Vn(t,e,i,s)}parseObjectData(t,e,i,s){const{iScale:n,vScale:o}=t,{xAxisKey:a="x",yAxisKey:r="y"}=this._parsing,l="x"===n.axis?a:r,h="x"===o.axis?a:r,c=[];let d,u,f,g;for(d=i,u=i+s;d<u;++d)g=e[d],f={},f[n.axis]=n.parse(M(g,l),d),c.push(Fn(M(g,h),f,o,d));return c}updateRangeFromParsed(t,e,i,s){super.updateRangeFromParsed(t,e,i,s);const n=i._custom;n&&e===this._cachedMeta.vScale&&(t.min=Math.min(t.min,n.min),t.max=Math.max(t.max,n.max))}getMaxOverflow(){return 0}getLabelAndValue(t){const e=this._cachedMeta,{iScale:i,vScale:s}=e,n=this.getParsed(t),o=n._custom,a=Bn(o)?"["+o.start+", "+o.end+"]":""+s.getLabelForValue(n[s.axis]);return{label:""+i.getLabelForValue(n[i.axis]),value:a}}initialize(){this.enableOptionSharing=!0,super.initialize();this._cachedMeta.stack=this.getDataset().stack}update(t){const e=this._cachedMeta;this.updateElements(e.data,0,e.data.length,t)}updateElements(t,e,i,n){const o="reset"===n,{index:a,_cachedMeta:{vScale:r}}=this,l=r.getBasePixel(),h=r.isHorizontal(),c=this._getRuler(),{sharedOptions:d,includeOptions:u}=this._getSharedOptions(e,n);for(let f=e;f<e+i;f++){const e=this.getParsed(f),i=o||s(e[r.axis])?{base:l,head:l}:this._calculateBarValuePixels(f),g=this._calculateBarIndexPixels(f,c),p=(e._stacks||{})[r.axis],m={horizontal:h,base:i.base,enableBorderRadius:!p||Bn(e._custom)||a===p._top||a===p._bottom,x:h?i.head:g.center,y:h?g.center:i.head,height:h?g.size:Math.abs(i.size),width:h?Math.abs(i.size):g.size};u&&(m.options=d||this.resolveDataElementOptions(f,t[f].active?"active":n));const x=m.options||t[f].options;Wn(m,x,p,a),jn(m,x,c.ratio),this.updateElement(t[f],f,m,n)}}_getStacks(t,e){const{iScale:i}=this._cachedMeta,n=i.getMatchingVisibleMetas(this._type).filter((t=>t.controller.options.grouped)),o=i.options.stacked,a=[],r=this._cachedMeta.controller.getParsed(e),l=r&&r[i.axis],h=t=>{const e=t._parsed.find((t=>t[i.axis]===l)),n=e&&e[t.vScale.axis];if(s(n)||isNaN(n))return!0};for(const i of n)if((void 0===e||!h(i))&&((!1===o||-1===a.indexOf(i.stack)||void 0===o&&void 0===i.stack)&&a.push(i.stack),i.index===t))break;return a.length||a.push(void 0),a}_getStackCount(t){return this._getStacks(void 0,t).length}_getAxisCount(){return this._getAxis().length}getFirstScaleIdForIndexAxis(){const t=this.chart.scales,e=this.chart.options.indexAxis;return Object.keys(t).filter((i=>t[i].axis===e)).shift()}_getAxis(){const t={},e=this.getFirstScaleIdForIndexAxis();for(const i of this.chart.data.datasets)t[l("x"===this.chart.options.indexAxis?i.xAxisID:i.yAxisID,e)]=!0;return Object.keys(t)}_getStackIndex(t,e,i){const s=this._getStacks(t,i),n=void 0!==e?s.indexOf(e):-1;return-1===n?s.length-1:n}_getRuler(){const t=this.options,e=this._cachedMeta,i=e.iScale,s=[];let n,o;for(n=0,o=e.data.length;n<o;++n)s.push(i.getPixelForValue(this.getParsed(n)[i.axis],n));const a=t.barThickness;return{min:a||zn(e),pixels:s,start:i._startPixel,end:i._endPixel,stackCount:this._getStackCount(),scale:i,grouped:t.grouped,ratio:a?1:t.categoryPercentage*t.barPercentage}}_calculateBarValuePixels(t){const{_cachedMeta:{vScale:e,_stacked:i,index:n},options:{base:o,minBarLength:a}}=this,r=o||0,l=this.getParsed(t),h=l._custom,c=Bn(h);let d,u,f=l[e.axis],g=0,p=i?this.applyStack(e,l,i):f;p!==f&&(g=p-f,p=f),c&&(f=h.barStart,p=h.barEnd-h.barStart,0!==f&&F(f)!==F(h.barEnd)&&(g=0),g+=f);const m=s(o)||c?g:o;let x=e.getPixelForValue(m);if(d=this.chart.getDataVisibility(t)?e.getPixelForValue(g+p):x,u=d-x,Math.abs(u)<a){u=function(t,e,i){return 0!==t?F(t):(e.isHorizontal()?1:-1)*(e.min>=i?1:-1)}(u,e,r)*a,f===r&&(x-=u/2);const t=e.getPixelForDecimal(0),s=e.getPixelForDecimal(1),o=Math.min(t,s),h=Math.max(t,s);x=Math.max(Math.min(x,h),o),d=x+u,i&&!c&&(l._stacks[e.axis]._visualValues[n]=e.getValueForPixel(d)-e.getValueForPixel(x))}if(x===e.getPixelForValue(r)){const t=F(u)*e.getLineWidthForValue(r)/2;x+=t,u-=t}return{size:u,base:x,head:d,center:d+u/2}}_calculateBarIndexPixels(t,e){const i=e.scale,n=this.options,o=n.skipNull,a=l(n.maxBarThickness,1/0);let r,h;const c=this._getAxisCount();if(e.grouped){const i=o?this._getStackCount(t):e.stackCount,d="flex"===n.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t<n.length-1?n[t+1]:null;const l=i.categoryPercentage;null===a&&(a=o-(null===r?e.end-e.start:r-o)),null===r&&(r=o+o-a);const h=o-(o-Math.min(a,r))/2*l;return{chunk:Math.abs(r-a)/2*l/s,ratio:i.barPercentage,start:h}}(t,e,n,i*c):function(t,e,i,n){const o=i.barThickness;let a,r;return s(o)?(a=e.min*i.categoryPercentage,r=i.barPercentage):(a=o*n,r=1),{chunk:a/n,ratio:r,start:e.pixels[t]-a/2}}(t,e,n,i*c),u="x"===this.chart.options.indexAxis?this.getDataset().xAxisID:this.getDataset().yAxisID,f=this._getAxis().indexOf(l(u,this.getFirstScaleIdForIndexAxis())),g=this._getStackIndex(this.index,this._cachedMeta.stack,o?t:void 0)+f;r=d.start+d.chunk*g+d.chunk/2,h=Math.min(a,d.chunk*d.ratio)}else r=i.getPixelForValue(this.getParsed(t)[i.axis],t),h=Math.min(a,e.min*e.ratio);return{base:r-h/2,head:r+h/2,center:r,size:h}}draw(){const t=this._cachedMeta,e=t.vScale,i=t.data,s=i.length;let n=0;for(;n<s;++n)null===this.getParsed(n)[e.axis]||i[n].hidden||i[n].draw(this._ctx)}},BubbleController:class extends js{static id="bubble";static defaults={datasetElementType:!1,dataElementType:"point",animations:{numbers:{type:"number",properties:["x","y","borderWidth","radius"]}}};static overrides={scales:{x:{type:"linear"},y:{type:"linear"}}};initialize(){this.enableOptionSharing=!0,super.initialize()}parsePrimitiveData(t,e,i,s){const n=super.parsePrimitiveData(t,e,i,s);for(let t=0;t<n.length;t++)n[t]._custom=this.resolveDataElementOptions(t+i).radius;return n}parseArrayData(t,e,i,s){const n=super.parseArrayData(t,e,i,s);for(let t=0;t<n.length;t++){const s=e[i+t];n[t]._custom=l(s[2],this.resolveDataElementOptions(t+i).radius)}return n}parseObjectData(t,e,i,s){const n=super.parseObjectData(t,e,i,s);for(let t=0;t<n.length;t++){const s=e[i+t];n[t]._custom=l(s&&s.r&&+s.r,this.resolveDataElementOptions(t+i).radius)}return n}getMaxOverflow(){const t=this._cachedMeta.data;let e=0;for(let i=t.length-1;i>=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart.data.labels||[],{xScale:s,yScale:n}=e,o=this.getParsed(t),a=s.getLabelForValue(o.x),r=n.getLabelForValue(o.y),l=o._custom;return{label:i[t]||"",value:"("+a+", "+r+(l?", "+l:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,{sharedOptions:r,includeOptions:l}=this._getSharedOptions(e,s),h=o.axis,c=a.axis;for(let d=e;d<e+i;d++){const e=t[d],i=!n&&this.getParsed(d),u={},f=u[h]=n?o.getPixelForDecimal(.5):o.getPixelForValue(i[h]),g=u[c]=n?a.getBasePixel():a.getPixelForValue(i[c]);u.skip=isNaN(f)||isNaN(g),l&&(u.options=r||this.resolveDataElementOptions(d,e.active?"active":s),n&&(u.options.radius=0)),this.updateElement(e,d,u,s)}}resolveDataElementOptions(t,e){const i=this.getParsed(t);let s=super.resolveDataElementOptions(t,e);s.$shared&&(s=Object.assign({},s,{$shared:!1}));const n=s.radius;return"active"!==e&&(s.radius=0),s.radius+=l(i&&i._custom,n),s}},DoughnutController:$n,LineController:class extends js{static id="line";static defaults={datasetElementType:"line",dataElementType:"point",showLine:!0,spanGaps:!1};static overrides={scales:{_index_:{type:"category"},_value_:{type:"linear"}}};initialize(){this.enableOptionSharing=!0,this.supportsDecimation=!0,super.initialize()}update(t){const e=this._cachedMeta,{dataset:i,data:s=[],_dataset:n}=e,o=this.chart._animationsDisabled;let{start:a,count:r}=pt(e,s,o);this._drawStart=a,this._drawCount=r,mt(e)&&(a=0,r=s.length),i._chart=this.chart,i._datasetIndex=this.index,i._decimated=!!n._decimated,i.points=s;const l=this.resolveDatasetElementOptions(t);this.options.showLine||(l.borderWidth=0),l.segment=this.options.segment,this.updateElement(i,void 0,{animated:!o,options:l},t),this.updateElements(s,a,r,t)}updateElements(t,e,i,n){const o="reset"===n,{iScale:a,vScale:r,_stacked:l,_dataset:h}=this._cachedMeta,{sharedOptions:c,includeOptions:d}=this._getSharedOptions(e,n),u=a.axis,f=r.axis,{spanGaps:g,segment:p}=this.options,m=N(g)?g:Number.POSITIVE_INFINITY,x=this.chart._animationsDisabled||o||"none"===n,b=e+i,_=t.length;let y=e>0&&this.getParsed(e-1);for(let i=0;i<_;++i){const g=t[i],_=x?g:{};if(i<e||i>=b){_.skip=!0;continue}const v=this.getParsed(i),M=s(v[f]),w=_[u]=a.getPixelForValue(v[u],i),k=_[f]=o||M?r.getBasePixel():r.getPixelForValue(l?this.applyStack(r,v,l):v[f],i);_.skip=isNaN(w)||isNaN(k)||M,_.stop=i>0&&Math.abs(v[u]-y[u])>m,p&&(_.parsed=v,_.raw=h.data[i]),d&&(_.options=c||this.resolveDataElementOptions(i,g.active?"active":n)),x||this.updateElement(g,i,_,n),y=v}}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}},PieController:class extends $n{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:Yn,RadarController:class extends js{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this._cachedMeta.rScale,o="reset"===s;for(let a=e;a<e+i;a++){const e=t[a],i=this.resolveDataElementOptions(a,e.active?"active":s),r=n.getPointPositionForValue(a,this.getParsed(a).r),l=o?n.xCenter:r.x,h=o?n.yCenter:r.y,c={x:l,y:h,angle:r.angle,skip:isNaN(l)||isNaN(h),options:i};this.updateElement(e,a,c,s)}}},ScatterController:class extends js{static id="scatter";static defaults={datasetElementType:!1,dataElementType:"point",showLine:!1,fill:!1};static overrides={interaction:{mode:"point"},scales:{x:{type:"linear"},y:{type:"linear"}}};getLabelAndValue(t){const e=this._cachedMeta,i=this.chart.data.labels||[],{xScale:s,yScale:n}=e,o=this.getParsed(t),a=s.getLabelForValue(o.x),r=n.getLabelForValue(o.y);return{label:i[t]||"",value:"("+a+", "+r+")"}}update(t){const e=this._cachedMeta,{data:i=[]}=e,s=this.chart._animationsDisabled;let{start:n,count:o}=pt(e,i,s);if(this._drawStart=n,this._drawCount=o,mt(e)&&(n=0,o=i.length),this.options.showLine){this.datasetElementType||this.addElements();const{dataset:n,_dataset:o}=e;n._chart=this.chart,n._datasetIndex=this.index,n._decimated=!!o._decimated,n.points=i;const a=this.resolveDatasetElementOptions(t);a.segment=this.options.segment,this.updateElement(n,void 0,{animated:!s,options:a},t)}else this.datasetElementType&&(delete e.dataset,this.datasetElementType=!1);this.updateElements(i,n,o,t)}addElements(){const{showLine:t}=this.options;!this.datasetElementType&&t&&(this.datasetElementType=this.chart.registry.getElement("line")),super.addElements()}updateElements(t,e,i,n){const o="reset"===n,{iScale:a,vScale:r,_stacked:l,_dataset:h}=this._cachedMeta,c=this.resolveDataElementOptions(e,n),d=this.getSharedOptions(c),u=this.includeOptions(n,d),f=a.axis,g=r.axis,{spanGaps:p,segment:m}=this.options,x=N(p)?p:Number.POSITIVE_INFINITY,b=this.chart._animationsDisabled||o||"none"===n;let _=e>0&&this.getParsed(e-1);for(let c=e;c<e+i;++c){const e=t[c],i=this.getParsed(c),p=b?e:{},y=s(i[g]),v=p[f]=a.getPixelForValue(i[f],c),M=p[g]=o||y?r.getBasePixel():r.getPixelForValue(l?this.applyStack(r,i,l):i[g],c);p.skip=isNaN(v)||isNaN(M)||y,p.stop=c>0&&Math.abs(i[f]-_[f])>x,m&&(p.parsed=i,p.raw=h.data[c]),u&&(p.options=d||this.resolveDataElementOptions(c,e.active?"active":n)),b||this.updateElement(e,c,p,n),_=i}this.updateSharedOptions(d,n,c)}getMaxOverflow(){const t=this._cachedMeta,e=t.data||[];if(!this.options.showLine){let t=0;for(let i=e.length-1;i>=0;--i)t=Math.max(t,e[i].size(this.resolveDataElementOptions(i))/2);return t>0&&t}const i=t.dataset,s=i.options&&i.options.borderWidth||0;if(!e.length)return s;const n=e[0].size(this.resolveDataElementOptions(0)),o=e[e.length-1].size(this.resolveDataElementOptions(e.length-1));return Math.max(s,n,o)/2}}});function Xn(t,e,i,s){const n=vi(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return Z(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:Z(n.innerStart,0,a),innerEnd:Z(n.innerEnd,0,a)}}function qn(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function Kn(t,e,i,s,n,o){const{x:a,y:r,startAngle:l,pixelMargin:h,innerRadius:c}=e,d=Math.max(e.outerRadius+s+i-h,0),u=c>0?c+s+i+h:0;let f=0;const g=n-l;if(s){const t=((c>0?c-s:0)+(d>0?d-s:0))/2;f=(g-(0!==t?g*t/(t+s):g))/2}const p=(g-Math.max(.001,g*d-i/C)/d)/2,m=l+p+f,x=n-p-f,{outerStart:b,outerEnd:_,innerStart:y,innerEnd:v}=Xn(e,u,d,x-m),M=d-b,w=d-_,k=m+b/M,S=x-_/w,P=u+y,D=u+v,O=m+y/P,A=x-v/D;if(t.beginPath(),o){const e=(k+S)/2;if(t.arc(a,r,d,k,e),t.arc(a,r,d,e,S),_>0){const e=qn(w,S,a,r);t.arc(e.x,e.y,_,S,x+E)}const i=qn(D,x,a,r);if(t.lineTo(i.x,i.y),v>0){const e=qn(D,A,a,r);t.arc(e.x,e.y,v,x+E,A+Math.PI)}const s=(x-v/u+(m+y/u))/2;if(t.arc(a,r,u,x-v/u,s,!0),t.arc(a,r,u,s,m+y/u,!0),y>0){const e=qn(P,O,a,r);t.arc(e.x,e.y,y,O+Math.PI,m-E)}const n=qn(M,m,a,r);if(t.lineTo(n.x,n.y),b>0){const e=qn(M,k,a,r);t.arc(e.x,e.y,b,m-E,k)}}else{t.moveTo(a,r);const e=Math.cos(k)*d+a,i=Math.sin(k)*d+r;t.lineTo(e,i);const s=Math.cos(S)*d+a,n=Math.sin(S)*d+r;t.lineTo(s,n)}t.closePath()}function Gn(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r,options:l}=e,{borderWidth:h,borderJoinStyle:c,borderDash:d,borderDashOffset:u,borderRadius:f}=l,g="inner"===l.borderAlign;if(!h)return;t.setLineDash(d||[]),t.lineDashOffset=u,g?(t.lineWidth=2*h,t.lineJoin=c||"round"):(t.lineWidth=h,t.lineJoin=c||"bevel");let p=e.endAngle;if(o){Kn(t,e,i,s,p,n);for(let e=0;e<o;++e)t.stroke();isNaN(r)||(p=a+(r%O||O))}g&&function(t,e,i){const{startAngle:s,pixelMargin:n,x:o,y:a,outerRadius:r,innerRadius:l}=e;let h=n/r;t.beginPath(),t.arc(o,a,r,s-h,i+h),l>n?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+E,s-E),t.closePath(),t.clip()}(t,e,p),l.selfJoin&&p-a>=C&&0===f&&"miter"!==c&&function(t,e,i){const{startAngle:s,x:n,y:o,outerRadius:a,innerRadius:r,options:l}=e,{borderWidth:h,borderJoinStyle:c}=l,d=Math.min(h/a,G(s-i));if(t.beginPath(),t.arc(n,o,a-h/2,s+d/2,i-d/2),r>0){const e=Math.min(h/r,G(s-i));t.arc(n,o,r+h/2,i-e/2,s+e/2,!0)}else{const e=Math.min(h/2,a*G(s-i));if("round"===c)t.arc(n,o,e,i-C/2,s+C/2,!0);else if("bevel"===c){const a=2*e*e,r=-a*Math.cos(i+C/2)+n,l=-a*Math.sin(i+C/2)+o,h=a*Math.cos(s+C/2)+n,c=a*Math.sin(s+C/2)+o;t.lineTo(r,l),t.lineTo(h,c)}}t.closePath(),t.moveTo(0,0),t.rect(0,0,t.canvas.width,t.canvas.height),t.clip("evenodd")}(t,e,p),o||(Kn(t,e,i,s,p,n),t.stroke())}function Jn(t,e,i=e){t.lineCap=l(i.borderCapStyle,e.borderCapStyle),t.setLineDash(l(i.borderDash,e.borderDash)),t.lineDashOffset=l(i.borderDashOffset,e.borderDashOffset),t.lineJoin=l(i.borderJoinStyle,e.borderJoinStyle),t.lineWidth=l(i.borderWidth,e.borderWidth),t.strokeStyle=l(i.borderColor,e.borderColor)}function Zn(t,e,i){t.lineTo(i.x,i.y)}function Qn(t,e,i={}){const s=t.length,{start:n=0,end:o=s-1}=i,{start:a,end:r}=e,l=Math.max(n,a),h=Math.min(o,r),c=n<a&&o<a||n>r&&o>r;return{count:s,start:l,loop:e.loop,ilen:h<l&&!c?s+h-l:h-l}}function to(t,e,i,s){const{points:n,options:o}=e,{count:a,start:r,loop:l,ilen:h}=Qn(n,i,s),c=function(t){return t.stepped?Fe:t.tension||"monotone"===t.cubicInterpolationMode?Ve:Zn}(o);let d,u,f,{move:g=!0,reverse:p}=s||{};for(d=0;d<=h;++d)u=n[(r+(p?h-d:d))%a],u.skip||(g?(t.moveTo(u.x,u.y),g=!1):c(t,f,u,p,o.stepped),f=u);return l&&(u=n[(r+(p?h:0))%a],c(t,f,u,p,o.stepped)),!!l}function eo(t,e,i,s){const n=e.points,{count:o,start:a,ilen:r}=Qn(n,i,s),{move:l=!0,reverse:h}=s||{};let c,d,u,f,g,p,m=0,x=0;const b=t=>(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[b(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[b(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(i<f?f=i:i>g&&(g=i),m=(x*m+e)/++x):(_(),t.lineTo(e,i),u=s,x=0,f=g=i),p=i}_()}function io(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?eo:to}const so="function"==typeof Path2D;function no(t,e,i,s){so&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Jn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=io(e);for(const r of n)Jn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class oo extends $s{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t&&"fill"!==t};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;hi(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=zi(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Ii(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?pi:t.tension||"monotone"===t.cubicInterpolationMode?mi:gi}(i);let l,h;for(l=0,h=o.length;l<h;++l){const{start:h,end:c}=o[l],d=n[h],u=n[c];if(d===u){a.push(d);continue}const f=r(d,u,Math.abs((s-d[e])/(u[e]-d[e])),i.stepped);f[e]=t[e],a.push(f)}return 1===a.length?a[0]:a}pathSegment(t,e,i){return io(this)(t,this,e,i)}path(t,e,i){const s=this.segments,n=io(this);let o=this._loop;e=e||0,i=i||this.points.length-e;for(const a of s)o&=n(t,this,a,{start:e,end:e+i-1});return!!o}draw(t,e,i,s){const n=this.options||{};(this.points||[]).length&&n.borderWidth&&(t.save(),no(t,this,i,s),t.restore()),this.animated&&(this._pointsUpdated=!1,this._path=void 0)}}function ao(t,e,i,s){const n=t.options,{[i]:o}=t.getProps([i],s);return Math.abs(e-o)<n.radius+n.hitRadius}function ro(t,e){const{x:i,y:s,base:n,width:o,height:a}=t.getProps(["x","y","base","width","height"],e);let r,l,h,c,d;return t.horizontal?(d=a/2,r=Math.min(i,n),l=Math.max(i,n),h=s-d,c=s+d):(d=o/2,r=i-d,l=i+d,h=Math.min(s,n),c=Math.max(s,n)),{left:r,top:h,right:l,bottom:c}}function lo(t,e,i,s){return t?0:Z(e,i,s)}function ho(t){const e=ro(t),i=e.right-e.left,s=e.bottom-e.top,n=function(t,e,i){const s=t.options.borderWidth,n=t.borderSkipped,o=Mi(s);return{t:lo(n.top,o.top,0,i),r:lo(n.right,o.right,0,e),b:lo(n.bottom,o.bottom,0,i),l:lo(n.left,o.left,0,e)}}(t,i/2,s/2),a=function(t,e,i){const{enableBorderRadius:s}=t.getProps(["enableBorderRadius"]),n=t.options.borderRadius,a=wi(n),r=Math.min(e,i),l=t.borderSkipped,h=s||o(n);return{topLeft:lo(!h||l.top||l.left,a.topLeft,0,r),topRight:lo(!h||l.top||l.right,a.topRight,0,r),bottomLeft:lo(!h||l.bottom||l.left,a.bottomLeft,0,r),bottomRight:lo(!h||l.bottom||l.right,a.bottomRight,0,r)}}(t,i/2,s/2);return{outer:{x:e.left,y:e.top,w:i,h:s,radius:a},inner:{x:e.left+n.l,y:e.top+n.t,w:i-n.l-n.r,h:s-n.t-n.b,radius:{topLeft:Math.max(0,a.topLeft-Math.max(n.t,n.l)),topRight:Math.max(0,a.topRight-Math.max(n.t,n.r)),bottomLeft:Math.max(0,a.bottomLeft-Math.max(n.b,n.l)),bottomRight:Math.max(0,a.bottomRight-Math.max(n.b,n.r))}}}}function co(t,e,i,s){const n=null===e,o=null===i,a=t&&!(n&&o)&&ro(t,s);return a&&(n||tt(e,a.left,a.right))&&(o||tt(i,a.top,a.bottom))}function uo(t,e){t.rect(e.x,e.y,e.w,e.h)}function fo(t,e,i={}){const s=t.x!==i.x?-e:0,n=t.y!==i.y?-e:0,o=(t.x+t.w!==i.x+i.w?e:0)-s,a=(t.y+t.h!==i.y+i.h?e:0)-n;return{x:t.x+s,y:t.y+n,w:t.w+o,h:t.h+a,radius:t.radius}}var go=Object.freeze({__proto__:null,ArcElement:class extends $s{static id="arc";static defaults={borderAlign:"center",borderColor:"#fff",borderDash:[],borderDashOffset:0,borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0,circular:!0,selfJoin:!1};static defaultRoutes={backgroundColor:"backgroundColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.getProps(["x","y"],i),{angle:n,distance:o}=X(s,{x:t,y:e}),{startAngle:a,endAngle:r,innerRadius:h,outerRadius:c,circumference:d}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],i),u=(this.options.spacing+this.options.borderWidth)/2,f=l(d,r-a),g=J(n,a,r)&&a!==r,p=f>=O||g,m=tt(o,h+u,c+u);return p&&m}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/4,n=(e.spacing||0)/2,o=e.circular;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>O?Math.floor(i/O):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();const a=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(a)*s,Math.sin(a)*s);const r=s*(1-Math.sin(Math.min(C,i||0)));t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor,function(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r}=e;let l=e.endAngle;if(o){Kn(t,e,i,s,l,n);for(let e=0;e<o;++e)t.fill();isNaN(r)||(l=a+(r%O||O))}Kn(t,e,i,s,l,n),t.fill()}(t,this,r,n,o),Gn(t,this,r,n,o),t.restore()}},BarElement:class extends $s{static id="bar";static defaults={borderSkipped:"start",borderWidth:0,borderRadius:0,inflateAmount:"auto",pointStyle:void 0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(t){super(),this.options=void 0,this.horizontal=void 0,this.base=void 0,this.width=void 0,this.height=void 0,this.inflateAmount=void 0,t&&Object.assign(this,t)}draw(t){const{inflateAmount:e,options:{borderColor:i,backgroundColor:s}}=this,{inner:n,outer:o}=ho(this),a=(r=o.radius).topLeft||r.topRight||r.bottomLeft||r.bottomRight?He:uo;var r;t.save(),o.w===n.w&&o.h===n.h||(t.beginPath(),a(t,fo(o,e,n)),t.clip(),a(t,fo(n,-e,o)),t.fillStyle=i,t.fill("evenodd")),t.beginPath(),a(t,fo(n,e)),t.fillStyle=s,t.fill(),t.restore()}inRange(t,e,i){return co(this,t,e,i)}inXRange(t,e){return co(this,t,null,e)}inYRange(t,e){return co(this,null,t,e)}getCenterPoint(t){const{x:e,y:i,base:s,horizontal:n}=this.getProps(["x","y","base","horizontal"],t);return{x:n?(e+s)/2:e,y:n?i:(i+s)/2}}getRange(t){return"x"===t?this.width/2:this.height/2}},LineElement:oo,PointElement:class extends $s{static id="point";parsed;skip;stop;static defaults={borderWidth:1,hitRadius:1,hoverBorderWidth:1,hoverRadius:4,pointStyle:"circle",radius:3,rotation:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(t){super(),this.options=void 0,this.parsed=void 0,this.skip=void 0,this.stop=void 0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.options,{x:n,y:o}=this.getProps(["x","y"],i);return Math.pow(t-n,2)+Math.pow(e-o,2)<Math.pow(s.hitRadius+s.radius,2)}inXRange(t,e){return ao(this,t,"x",e)}inYRange(t,e){return ao(this,t,"y",e)}getCenterPoint(t){const{x:e,y:i}=this.getProps(["x","y"],t);return{x:e,y:i}}size(t){let e=(t=t||this.options||{}).radius||0;e=Math.max(e,e&&t.hoverRadius||0);return 2*(e+(e&&t.borderWidth||0))}draw(t,e){const i=this.options;this.skip||i.radius<.1||!Re(this,e,this.size(i)/2)||(t.strokeStyle=i.borderColor,t.lineWidth=i.borderWidth,t.fillStyle=i.backgroundColor,Le(t,i,this.x,this.y))}getRange(){const t=this.options||{};return t.radius+t.hitRadius}}});function po(t,e,i,s){const n=t.indexOf(e);if(-1===n)return((t,e,i,s)=>("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}function mo(t){const e=this.getLabels();return t>=0&&t<e.length?e[t]:t}function xo(t,e,{horizontal:i,minRotation:s}){const n=$(s),o=(i?Math.sin(n):Math.cos(n))||.001,a=.75*e*(""+t).length;return Math.min(e/o,a)}class bo extends tn{constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(t,e){return s(t)||("number"==typeof t||t instanceof Number)&&!isFinite(+t)?null:+t}handleTickRangeOptions(){const{beginAtZero:t}=this.options,{minDefined:e,maxDefined:i}=this.getUserBounds();let{min:s,max:n}=this;const o=t=>s=e?s:t,a=t=>n=i?n:t;if(t){const t=F(s),e=F(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=0===n?1:Math.abs(.05*n);a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const n=function(t,e){const i=[],{bounds:n,step:o,min:a,max:r,precision:l,count:h,maxTicks:c,maxDigits:d,includeBounds:u}=t,f=o||1,g=c-1,{min:p,max:m}=e,x=!s(a),b=!s(r),_=!s(h),y=(m-p)/(d+1);let v,M,w,k,S=B((m-p)/g/f)*f;if(S<1e-14&&!x&&!b)return[{value:p},{value:m}];k=Math.ceil(m/S)-Math.floor(p/S),k>g&&(S=B(k*S/g/f)*f),s(l)||(v=Math.pow(10,l),S=Math.ceil(S*v)/v),"ticks"===n?(M=Math.floor(p/S)*S,w=Math.ceil(m/S)*S):(M=p,w=m),x&&b&&o&&H((r-a)/o,S/1e3)?(k=Math.round(Math.min((r-a)/S,c)),S=(r-a)/k,M=a,w=r):_?(M=x?a:M,w=b?r:w,k=h-1,S=(w-M)/k):(k=(w-M)/S,k=V(k,Math.round(k),S/1e3)?Math.round(k):Math.ceil(k));const P=Math.max(U(S),U(M));v=Math.pow(10,s(l)?P:l),M=Math.round(M*v)/v,w=Math.round(w*v)/v;let D=0;for(x&&(u&&M!==a?(i.push({value:a}),M<a&&D++,V(Math.round((M+D*S)*v)/v,a,xo(a,y,t))&&D++):M<a&&D++);D<k;++D){const t=Math.round((M+D*S)*v)/v;if(b&&t>r)break;i.push({value:t})}return b&&u&&w!==r?i.length&&V(i[i.length-1].value,r,xo(r,y,t))?i[i.length-1].value=r:i.push({value:r}):b&&w!==r||i.push({value:w}),i}({maxTicks:i,bounds:t.bounds,min:t.min,max:t.max,precision:e.precision,step:e.stepSize,count:e.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:e.minRotation||0,includeBounds:!1!==e.includeBounds},this._range||this);return"ticks"===t.bounds&&j(n,this,"value"),t.reverse?(n.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),n}configure(){const t=this.ticks;let e=this.min,i=this.max;if(super.configure(),this.options.offset&&t.length){const s=(i-e)/Math.max(t.length-1,1)/2;e-=s,i+=s}this._startValue=e,this._endValue=i,this._valueRange=i-e}getLabelForValue(t){return ne(t,this.chart.options.locale,this.options.ticks.format)}}class _o extends bo{static id="linear";static defaults={ticks:{callback:ae.formatters.numeric}};determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?t:0,this.max=a(e)?e:1,this.handleTickRangeOptions()}computeTickLimit(){const t=this.isHorizontal(),e=t?this.width:this.height,i=$(this.options.ticks.minRotation),s=(t?Math.sin(i):Math.cos(i))||.001,n=this._resolveTickFontOptions(0);return Math.ceil(e/Math.min(40,n.lineHeight/s))}getPixelForValue(t){return null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getValueForPixel(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange}}const yo=t=>Math.floor(z(t)),vo=(t,e)=>Math.pow(10,yo(t)+e);function Mo(t){return 1===t/Math.pow(10,yo(t))}function wo(t,e,i){const s=Math.pow(10,i),n=Math.floor(t/s);return Math.ceil(e/s)-n}function ko(t,{min:e,max:i}){e=r(t.min,e);const s=[],n=yo(e);let o=function(t,e){let i=yo(e-t);for(;wo(t,e,i)>10;)i++;for(;wo(t,e,i)<10;)i--;return Math.min(i,yo(t))}(e,i),a=o<0?Math.pow(10,Math.abs(o)):1;const l=Math.pow(10,o),h=n>o?Math.pow(10,n):0,c=Math.round((e-h)*a)/a,d=Math.floor((e-h)/l/10)*l*10;let u=Math.floor((c-d)/Math.pow(10,o)),f=r(t.min,Math.round((h+d+u*Math.pow(10,o))*a)/a);for(;f<i;)s.push({value:f,major:Mo(f),significand:u}),u>=10?u=u<15?15:20:u++,u>=20&&(o++,u=2,a=o>=0?1:a),f=Math.round((h+d+u*Math.pow(10,o))*a)/a;const g=r(t.max,f);return s.push({value:g,major:Mo(g),significand:u}),s}class So extends tn{static id="logarithmic";static defaults={ticks:{callback:ae.formatters.logarithmic,major:{enabled:!0}}};constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(t,e){const i=bo.prototype.parse.apply(this,[t,e]);if(0!==i)return a(i)&&i>0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?Math.max(0,t):null,this.max=a(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!a(this._userMin)&&(this.min=t===vo(this.min,0)?vo(this.min,-1):vo(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t;i===s&&(i<=0?(n(1),o(10)):(n(vo(i,-1)),o(vo(s,1)))),i<=0&&n(vo(s,-1)),s<=0&&o(vo(i,1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=ko({min:this._userMin,max:this._userMax},this);return"ticks"===t.bounds&&j(e,this,"value"),t.reverse?(e.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),e}getLabelForValue(t){return void 0===t?"0":ne(t,this.chart.options.locale,this.options.ticks.format)}configure(){const t=this.min;super.configure(),this._startValue=z(t),this._valueRange=z(this.max)-z(t)}getPixelForValue(t){return void 0!==t&&0!==t||(t=this.min),null===t||isNaN(t)?NaN:this.getPixelForDecimal(t===this.min?0:(z(t)-this._startValue)/this._valueRange)}getValueForPixel(t){const e=this.getDecimalForPixel(t);return Math.pow(10,this._startValue+e*this._valueRange)}}function Po(t){const e=t.ticks;if(e.display&&t.display){const t=ki(e.backdropPadding);return l(e.font&&e.font.size,ue.font.size)+t.height}return 0}function Do(t,e,i,s,n){return t===s||t===n?{start:e-i/2,end:e+i/2}:t<s||t>n?{start:e-i,end:e}:{start:e,end:e+i}}function Co(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],o=[],a=t._pointLabels.length,r=t.options.pointLabels,l=r.centerPointLabels?C/a:0;for(let u=0;u<a;u++){const a=r.setContext(t.getPointLabelContext(u));o[u]=a.padding;const f=t.getPointPosition(u,t.drawingArea+o[u],l),g=Si(a.font),p=(h=t.ctx,c=g,d=n(d=t._pointLabels[u])?d:[d],{w:Oe(h,c.string,d),h:d.length*c.lineHeight});s[u]=p;const m=G(t.getIndexAngle(u)+l),x=Math.round(Y(m));Oo(i,e,m,Do(x,f.x,p.w,0,180),Do(x,f.y,p.h,90,270))}var h,c,d;t.setCenterPoint(e.l-i.l,i.r-e.r,e.t-i.t,i.b-e.b),t._pointLabelItems=function(t,e,i){const s=[],n=t._pointLabels.length,o=t.options,{centerPointLabels:a,display:r}=o.pointLabels,l={extra:Po(o)/2,additionalAngle:a?C/n:0};let h;for(let o=0;o<n;o++){l.padding=i[o],l.size=e[o];const n=Ao(t,o,l);s.push(n),"auto"===r&&(n.visible=To(n,h),n.visible&&(h=n))}return s}(t,s,o)}function Oo(t,e,i,s,n){const o=Math.abs(Math.sin(i)),a=Math.abs(Math.cos(i));let r=0,l=0;s.start<e.l?(r=(e.l-s.start)/o,t.l=Math.min(t.l,e.l-r)):s.end>e.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.start<e.t?(l=(e.t-n.start)/a,t.t=Math.min(t.t,e.t-l)):n.end>e.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function Ao(t,e,i){const s=t.drawingArea,{extra:n,additionalAngle:o,padding:a,size:r}=i,l=t.getPointPosition(e,s+n+a,o),h=Math.round(Y(G(l.angle+E))),c=function(t,e,i){90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e);return t}(l.y,r.h,h),d=function(t){if(0===t||180===t)return"center";if(t<180)return"left";return"right"}(h),u=function(t,e,i){"right"===i?t-=e:"center"===i&&(t-=e/2);return t}(l.x,r.w,d);return{visible:!0,x:l.x,y:c,textAlign:d,left:u,top:c,right:u+r.w,bottom:c+r.h}}function To(t,e){if(!e)return!0;const{left:i,top:s,right:n,bottom:o}=t;return!(Re({x:i,y:s},e)||Re({x:i,y:o},e)||Re({x:n,y:s},e)||Re({x:n,y:o},e))}function Lo(t,e,i){const{left:n,top:o,right:a,bottom:r}=i,{backdropColor:l}=e;if(!s(l)){const i=wi(e.borderRadius),s=ki(e.backdropPadding);t.fillStyle=l;const h=n-s.left,c=o-s.top,d=a-n+s.width,u=r-o+s.height;Object.values(i).some((t=>0!==t))?(t.beginPath(),He(t,{x:h,y:c,w:d,h:u,radius:i}),t.fill()):t.fillRect(h,c,d,u)}}function Eo(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,O);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;o<s;o++)i=t.getPointPosition(o,e),n.lineTo(i.x,i.y)}}class Ro extends bo{static id="radialLinear";static defaults={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:ae.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback:t=>t,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(t){super(t),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){const t=this._padding=ki(Po(this.options)/2),e=this.width=this.maxWidth-t.width,i=this.height=this.maxHeight-t.height;this.xCenter=Math.floor(this.left+e/2+t.left),this.yCenter=Math.floor(this.top+i/2+t.top),this.drawingArea=Math.floor(Math.min(e,i)/2)}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!1);this.min=a(t)&&!isNaN(t)?t:0,this.max=a(e)&&!isNaN(e)?e:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/Po(this.options))}generateTickLabels(t){bo.prototype.generateTickLabels.call(this,t),this._pointLabels=this.getLabels().map(((t,e)=>{const i=d(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?Co(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return G(t*(O/(this._pointLabels.length||1))+$(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if(s(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if(s(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t<e.length){const i=e[t];return function(t,e,i){return Ci(t,{label:i,index:e,type:"pointLabel"})}(this.getContext(),t,i)}}getPointPosition(t,e,i=0){const s=this.getIndexAngle(t)-E+i;return{x:Math.cos(s)*e+this.xCenter,y:Math.sin(s)*e+this.yCenter,angle:s}}getPointPositionForValue(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))}getBasePosition(t){return this.getPointPositionForValue(t||0,this.getBaseValue())}getPointLabelPosition(t){const{left:e,top:i,right:s,bottom:n}=this._pointLabelItems[t];return{left:e,top:i,right:s,bottom:n}}drawBackground(){const{backgroundColor:t,grid:{circular:e}}=this.options;if(t){const i=this.ctx;i.save(),i.beginPath(),Eo(this,this.getDistanceFromCenterForValue(this._endValue),e,this._pointLabels.length),i.closePath(),i.fillStyle=t,i.fill(),i.restore()}}drawGrid(){const t=this.ctx,e=this.options,{angleLines:i,grid:s,border:n}=e,o=this._pointLabels.length;let a,r,l;if(e.pointLabels.display&&function(t,e){const{ctx:i,options:{pointLabels:s}}=t;for(let n=e-1;n>=0;n--){const e=t._pointLabelItems[n];if(!e.visible)continue;const o=s.setContext(t.getPointLabelContext(n));Lo(i,o,e);const a=Si(o.font),{x:r,y:l,textAlign:h}=e;Ne(i,t._pointLabels[n],r,l+a.lineHeight/2,a,{color:o.color,textAlign:h,textBaseline:"middle"})}}(this,o),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e||0===e&&this.min<0){r=this.getDistanceFromCenterForValue(t.value);const i=this.getContext(e),a=s.setContext(i),l=n.setContext(i);!function(t,e,i,s,n){const o=t.ctx,a=e.circular,{color:r,lineWidth:l}=e;!a&&!s||!r||!l||i<0||(o.save(),o.strokeStyle=r,o.lineWidth=l,o.setLineDash(n.dash||[]),o.lineDashOffset=n.dashOffset,o.beginPath(),Eo(t,i,a,s),o.closePath(),o.stroke(),o.restore())}(this,a,r,o,l)}})),i.display){for(t.save(),a=o-1;a>=0;a--){const s=i.setContext(this.getPointLabelContext(a)),{color:n,lineWidth:o}=s;o&&n&&(t.lineWidth=o,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,r=this.getDistanceFromCenterForValue(e.reverse?this.min:this.max),l=this.getPointPosition(a,r),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(l.x,l.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&this.min>=0&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=Si(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=ki(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}Ne(t,s.label,0,-n,l,{color:r.color,strokeColor:r.textStrokeColor,strokeWidth:r.textStrokeWidth})})),t.restore()}drawTitle(){}}const Io={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},zo=Object.keys(Io);function Fo(t,e){return t-e}function Vo(t,e){if(s(e))return null;const i=t._adapter,{parser:n,round:o,isoWeekday:r}=t._parseOpts;let l=e;return"function"==typeof n&&(l=n(l)),a(l)||(l="string"==typeof n?i.parse(l,n):i.parse(l)),null===l?null:(o&&(l="week"!==o||!N(r)&&!0!==r?i.startOf(l,o):i.startOf(l,"isoWeek",r)),+l)}function Bo(t,e,i,s){const n=zo.length;for(let o=zo.indexOf(t);o<n-1;++o){const t=Io[zo[o]],n=t.steps?t.steps:Number.MAX_SAFE_INTEGER;if(t.common&&Math.ceil((i-e)/(n*t.size))<=s)return zo[o]}return zo[n-1]}function Wo(t,e,i){if(i){if(i.length){const{lo:s,hi:n}=et(i,e);t[i[s]>=e?i[s]:i[n]]=!0}}else t[e]=!0}function No(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a<o;++a)r=e[a],n[r]=a,s.push({value:r,major:!1});return 0!==o&&i?function(t,e,i,s){const n=t._adapter,o=+n.startOf(e[0].value,s),a=e[e.length-1].value;let r,l;for(r=o;r<=a;r=+n.add(r,1,s))l=i[r],l>=0&&(e[l].major=!0);return e}(t,s,n,i):s}class Ho extends tn{static id="time";static defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",callback:!1,major:{enabled:!1}}};constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e={}){const i=t.time||(t.time={}),s=this._adapter=new In._date(t.adapters.date);s.init(e),b(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:Vo(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:r}=this.getUserBounds();function l(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),r||isNaN(t.max)||(n=Math.max(n,t.max))}o&&r||(l(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||l(this.getMinMax(!1))),s=a(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=a(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=nt(s,n,this.max);return this._unit=e.unit||(i.autoSkip?Bo(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=zo.length-1;o>=zo.indexOf(i);o--){const i=zo[o];if(Io[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return zo[i?zo.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=zo.indexOf(t)+1,i=zo.length;e<i;++e)if(Io[zo[e]].common)return zo[e]}(this._unit):void 0,this.initOffsets(s),t.reverse&&o.reverse(),No(this,o,this._majorUnit)}afterAutoSkip(){this.options.offsetAfterAutoskip&&this.initOffsets(this.ticks.map((t=>+t.value)))}initOffsets(t=[]){let e,i,s=0,n=0;this.options.offset&&t.length&&(e=this.getDecimalForValue(t[0]),s=1===t.length?1-e:(this.getDecimalForValue(t[1])-e)/2,i=this.getDecimalForValue(t[t.length-1]),n=1===t.length?i:(i-this.getDecimalForValue(t[t.length-2]))/2);const o=t.length<3?.5:.25;s=Z(s,0,o),n=Z(n,0,o),this._offsets={start:s,end:n,factor:1/(s+1+n)}}_generate(){const t=this._adapter,e=this.min,i=this.max,s=this.options,n=s.time,o=n.unit||Bo(n.minUnit,e,i,this._getLabelCapacity(e)),a=l(s.ticks.stepSize,1),r="week"===o&&n.isoWeekday,h=N(r)||!0===r,c={};let d,u,f=e;if(h&&(f=+t.startOf(f,"isoWeek",r)),f=+t.startOf(f,h?"day":o),t.diff(i,e,o)>1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const g="data"===s.ticks.source&&this.getDataTimestamps();for(d=f,u=0;d<i;d=+t.add(d,a,o),u++)Wo(c,d,g);return d!==i&&"ticks"!==s.bounds&&1!==u||Wo(c,d,g),Object.keys(c).sort(Fo).map((t=>+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}format(t,e){const i=this.options.time.displayFormats,s=this._unit,n=e||i[s];return this._adapter.format(t,n)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.ticks.callback;if(o)return d(o,[t,e,i],this);const a=n.time.displayFormats,r=this._unit,l=this._majorUnit,h=r&&a[r],c=l&&a[l],u=i[e],f=l&&c&&u&&u.major;return this._adapter.format(t,s||(f?c:h))}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e<i;++e)s=t[e],s.label=this._tickFormatFunction(s.value,e,t)}getDecimalForValue(t){return null===t?NaN:(t-this.min)/(this.max-this.min)}getPixelForValue(t){const e=this._offsets,i=this.getDecimalForValue(t);return this.getPixelForDecimal((e.start+i)*e.factor)}getValueForPixel(t){const e=this._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end;return this.min+i*(this.max-this.min)}_getLabelSize(t){const e=this.options.ticks,i=this.ctx.measureText(t).width,s=$(this.isHorizontal()?e.maxRotation:e.minRotation),n=Math.cos(s),o=Math.sin(s),a=this._resolveTickFontOptions(0).size;return{w:i*n+a*o,h:i*o+a*n}}_getLabelCapacity(t){const e=this.options.time,i=e.displayFormats,s=i[e.unit]||i.millisecond,n=this._tickFormatFunction(t,0,No(this,[t],this._majorUnit),s),o=this._getLabelSize(n),a=Math.floor(this.isHorizontal()?this.width/o.w:this.height/o.h)-1;return a>0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t<e;++t)i=i.concat(s[t].controller.getAllParsedValues(this));return this._cache.data=this.normalize(i)}getLabelTimestamps(){const t=this._cache.labels||[];let e,i;if(t.length)return t;const s=this.getLabels();for(e=0,i=s.length;e<i;++e)t.push(Vo(this,s[e]));return this._cache.labels=this._normalized?t:this.normalize(t)}normalize(t){return lt(t.sort(Fo))}}function jo(t,e,i){let s,n,o,a,r=0,l=t.length-1;i?(e>=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=it(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=it(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}var $o=Object.freeze({__proto__:null,CategoryScale:class extends tn{static id="category";static defaults={ticks:{callback:mo}};constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if(s(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:Z(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:po(i,t,l(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){return mo.call(this,t)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(t){return"number"!=typeof t&&(t=this.parse(t)),null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:_o,LogarithmicScale:So,RadialLinearScale:Ro,TimeScale:Ho,TimeSeriesScale:class extends Ho{static id="timeseries";static defaults=Ho.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=jo(e,this.min),this._tableRange=jo(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o<a;++o)l=t[o],l>=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;o<a;++o)h=s[o+1],r=s[o-1],l=s[o],Math.round((h+r)/2)!==l&&n.push({time:l,pos:o/(a-1)});return n}_generate(){const t=this.min,e=this.max;let i=super.getDataTimestamps();return i.includes(t)&&i.length||i.splice(0,0,t),i.includes(e)&&1!==i.length||i.push(e),i.sort(((t,e)=>t-e))}_getTimestampsForTable(){let t=this._cache.all||[];if(t.length)return t;const e=this.getDataTimestamps(),i=this.getLabelTimestamps();return t=e.length&&i.length?this.normalize(e.concat(i)):e.length?e:i,t=this._cache.all=t,t}getDecimalForValue(t){return(jo(this._table,t)-this._minPos)/this._tableRange}getValueForPixel(t){const e=this._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end;return jo(this._table,i*this._tableRange+this._minPos,!0)}}});const Yo=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],Uo=Yo.map((t=>t.replace("rgb(","rgba(").replace(")",", 0.5)")));function Xo(t){return Yo[t%Yo.length]}function qo(t){return Uo[t%Uo.length]}function Ko(t){let e=0;return(i,s)=>{const n=t.getDatasetMeta(s).controller;n instanceof $n?e=function(t,e){return t.backgroundColor=t.data.map((()=>Xo(e++))),e}(i,e):n instanceof Yn?e=function(t,e){return t.backgroundColor=t.data.map((()=>qo(e++))),e}(i,e):n&&(e=function(t,e){return t.borderColor=Xo(e),t.backgroundColor=qo(e),++e}(i,e))}}function Go(t){let e;for(e in t)if(t[e].borderColor||t[e].backgroundColor)return!0;return!1}var Jo={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(t,e,i){if(!i.enabled)return;const{data:{datasets:s},options:n}=t.config,{elements:o}=n,a=Go(s)||(r=n)&&(r.borderColor||r.backgroundColor)||o&&Go(o)||"rgba(0,0,0,0.1)"!==ue.borderColor||"rgba(0,0,0,0.1)"!==ue.backgroundColor;var r;if(!i.forceOverride&&a)return;const l=Ko(t);s.forEach(l)}};function Zo(t){if(t._decimated){const e=t._data;delete t._decimated,delete t._data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,writable:!0,value:e})}}function Qo(t){t.data.datasets.forEach((t=>{Zo(t)}))}var ta={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void Qo(t);const n=t.width;t.data.datasets.forEach(((e,o)=>{const{_data:a,indexAxis:r}=e,l=t.getDatasetMeta(o),h=a||e.data;if("y"===Pi([r,t.options.indexAxis]))return;if(!l.controller.supportsDecimation)return;const c=t.scales[l.xAxisID];if("linear"!==c.type&&"time"!==c.type)return;if(t.options.parsing)return;let{start:d,count:u}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=Z(it(e,o.axis,a).lo,0,i-1)),s=h?Z(it(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(l,h);if(u<=(i.threshold||4*n))return void Zo(e);let f;switch(s(a)&&(e._data=h,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":f=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;c<o-2;c++){let s,n=0,o=0;const h=Math.floor((c+1)*r)+1+e,m=Math.min(Math.floor((c+2)*r)+1,i)+e,x=m-h;for(s=h;s<m;s++)n+=t[s].x,o+=t[s].y;n/=x,o/=x;const b=Math.floor(c*r)+1+e,_=Math.min(Math.floor((c+1)*r)+1,i)+e,{x:y,y:v}=t[p];for(u=f=-1,s=b;s<_;s++)f=.5*Math.abs((y-n)*(t[s].y-v)-(y-t[s].x)*(o-v)),f>u&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(h,d,u,n,i);break;case"min-max":f=function(t,e,i,n){let o,a,r,l,h,c,d,u,f,g,p=0,m=0;const x=[],b=e+i-1,_=t[e].x,y=t[b].x-_;for(o=e;o<e+i;++o){a=t[o],r=(a.x-_)/y*n,l=a.y;const e=0|r;if(e===h)l<f?(f=l,c=o):l>g&&(g=l,d=o),p=(m*p+a.x)/++m;else{const i=o-1;if(!s(c)&&!s(d)){const e=Math.min(c,d),s=Math.max(c,d);e!==u&&e!==i&&x.push({...t[e],x:p}),s!==u&&s!==i&&x.push({...t[s],x:p})}o>0&&i!==u&&x.push(t[i]),x.push(a),h=e,m=0,f=g=l,c=d=u=o}}return x}(h,d,u,n);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=f}))},destroy(t){Qo(t)}};function ea(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=G(n),o=G(o)),{property:t,start:n,end:o}}function ia(t,e,i){for(;e>t;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function sa(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function na(t,e){let i=[],s=!1;return n(t)?(s=!0,i=t):i=function(t,e){const{x:i=null,y:s=null}=t||{},n=e.points,o=[];return e.segments.forEach((({start:t,end:e})=>{e=ia(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new oo({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function oa(t){return t&&!1!==t.fill}function aa(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!a(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function ra(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=l(i&&i.target,i);void 0===s&&(s=!!e.backgroundColor);if(!1===s||null===s)return!1;if(!0===s)return"origin";return s}(t);if(o(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return a(n)&&Math.floor(n)===n?function(t,e,i,s){"-"!==t&&"+"!==t||(i=e+i);if(i===e||i<0||i>=s)return!1;return i}(s[0],e,n,i):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}function la(t,e,i){const s=[];for(let n=0;n<i.length;n++){const o=i[n],{first:a,last:r,point:l}=ha(o,e,"x");if(!(!l||a&&r))if(a)s.unshift(l);else if(t.push(l),!r)break}t.push(...s)}function ha(t,e,i){const s=t.interpolate(e,i);if(!s)return{};const n=s[i],o=t.segments,a=t.points;let r=!1,l=!1;for(let t=0;t<o.length;t++){const e=o[t],s=a[e.start][i],h=a[e.end][i];if(tt(n,s,h)){r=n===s,l=n===h;break}}return{first:r,last:l,point:s}}class ca{constructor(t){this.x=t.x,this.y=t.y,this.radius=t.radius}pathSegment(t,e,i){const{x:s,y:n,radius:o}=this;return e=e||{start:0,end:O},t.arc(s,n,o,e.end,e.start,!0),!i.bounds}interpolate(t){const{x:e,y:i,radius:s}=this,n=t.angle;return{x:e+Math.cos(n)*s,y:i+Math.sin(n)*s,angle:n}}}function da(t){const{chart:e,fill:i,line:s}=t;if(a(i))return function(t,e){const i=t.getDatasetMeta(e),s=i&&t.isDatasetVisible(e);return s?i.dataset:null}(e,i);if("stack"===i)return function(t){const{scale:e,index:i,line:s}=t,n=[],o=s.segments,a=s.points,r=function(t,e){const i=[],s=t.getMatchingVisibleMetas("line");for(let t=0;t<s.length;t++){const n=s[t];if(n.index===e)break;n.hidden||i.unshift(n.dataset)}return i}(e,i);r.push(na({x:null,y:e.bottom},s));for(let t=0;t<o.length;t++){const e=o[t];for(let t=e.start;t<=e.end;t++)la(n,a[t],r)}return new oo({points:n,options:{}})}(t);if("shape"===i)return!0;const n=function(t){const e=t.scale||{};if(e.getPointPositionForValue)return function(t){const{scale:e,fill:i}=t,s=e.options,n=e.getLabels().length,a=s.reverse?e.max:e.min,r=function(t,e,i){let s;return s="start"===t?i:"end"===t?e.options.reverse?e.min:e.max:o(t)?t.value:e.getBaseValue(),s}(i,e,a),l=[];if(s.grid.circular){const t=e.getPointPositionForValue(0,a);return new ca({x:t.x,y:t.y,radius:e.getDistanceFromCenterForValue(r)})}for(let t=0;t<n;++t)l.push(e.getPointPositionForValue(t,r));return l}(t);return function(t){const{scale:e={},fill:i}=t,s=function(t,e){let i=null;return"start"===t?i=e.bottom:"end"===t?i=e.top:o(t)?i=e.getPixelForValue(t.value):e.getBasePixel&&(i=e.getBasePixel()),i}(i,e);if(a(s)){const t=e.isHorizontal();return{x:t?s:null,y:t?null:s}}return null}(t)}(t);return n instanceof ca?n:na(n,s)}function ua(t,e,i){const s=da(e),{chart:n,index:o,line:a,scale:r,axis:l}=e,h=a.options,c=h.fill,d=h.backgroundColor,{above:u=d,below:f=d}=c||{},g=n.getDatasetMeta(o),p=Ni(n,g);s&&a.points.length&&(Ie(t,i),function(t,e){const{line:i,target:s,above:n,below:o,area:a,scale:r,clip:l}=e,h=i._loop?"angle":e.axis;t.save();let c=o;o!==n&&("x"===h?(fa(t,s,a.top),pa(t,{line:i,target:s,color:n,scale:r,property:h,clip:l}),t.restore(),t.save(),fa(t,s,a.bottom)):"y"===h&&(ga(t,s,a.left),pa(t,{line:i,target:s,color:o,scale:r,property:h,clip:l}),t.restore(),t.save(),ga(t,s,a.right),c=n));pa(t,{line:i,target:s,color:c,scale:r,property:h,clip:l}),t.restore()}(t,{line:a,target:s,above:u,below:f,area:i,scale:r,axis:l,clip:p}),ze(t))}function fa(t,e,i){const{segments:s,points:n}=e;let o=!0,a=!1;t.beginPath();for(const r of s){const{start:s,end:l}=r,h=n[s],c=n[ia(s,l,n)];o?(t.moveTo(h.x,h.y),o=!1):(t.lineTo(h.x,i),t.lineTo(h.x,h.y)),a=!!e.pathSegment(t,r,{move:a}),a?t.closePath():t.lineTo(c.x,i)}t.lineTo(e.first().x,i),t.closePath(),t.clip()}function ga(t,e,i){const{segments:s,points:n}=e;let o=!0,a=!1;t.beginPath();for(const r of s){const{start:s,end:l}=r,h=n[s],c=n[ia(s,l,n)];o?(t.moveTo(h.x,h.y),o=!1):(t.lineTo(i,h.y),t.lineTo(h.x,h.y)),a=!!e.pathSegment(t,r,{move:a}),a?t.closePath():t.lineTo(i,c.y)}t.lineTo(i,e.first().y),t.closePath(),t.clip()}function pa(t,e){const{line:i,target:s,property:n,color:o,scale:a,clip:r}=e,l=function(t,e,i){const s=t.segments,n=t.points,o=e.points,a=[];for(const t of s){let{start:s,end:r}=t;r=ia(s,r,n);const l=ea(i,n[s],n[r],t.loop);if(!e.segments){a.push({source:t,target:l,start:n[s],end:n[r]});continue}const h=Ii(e,l);for(const e of h){const s=ea(i,o[e.start],o[e.end],e.loop),r=Ri(t,n,s);for(const t of r)a.push({source:t,target:e,start:{[i]:sa(l,s,"start",Math.max)},end:{[i]:sa(l,s,"end",Math.min)}})}}return a}(i,s,n);for(const{source:e,target:h,start:c,end:d}of l){const{style:{backgroundColor:l=o}={}}=e,u=!0!==s;t.save(),t.fillStyle=l,ma(t,a,r,u&&ea(n,c,d)),t.beginPath();const f=!!i.pathSegment(t,e);let g;if(u){f?t.closePath():xa(t,s,d,n);const e=!!s.pathSegment(t,h,{move:f,reverse:!0});g=f&&e,g||xa(t,s,c,n)}t.closePath(),t.fill(g?"evenodd":"nonzero"),t.restore()}}function ma(t,e,i,s){const n=e.chart.chartArea,{property:o,start:a,end:r}=s||{};if("x"===o||"y"===o){let e,s,l,h;"x"===o?(e=a,s=n.top,l=r,h=n.bottom):(e=n.left,s=a,l=n.right,h=r),t.beginPath(),i&&(e=Math.max(e,i.left),l=Math.min(l,i.right),s=Math.max(s,i.top),h=Math.min(h,i.bottom)),t.rect(e,s,l-e,h-s),t.clip()}}function xa(t,e,i,s){const n=e.interpolate(i,s);n&&t.lineTo(n.x,n.y)}var ba={id:"filler",afterDatasetsUpdate(t,e,i){const s=(t.data.datasets||[]).length,n=[];let o,a,r,l;for(a=0;a<s;++a)o=t.getDatasetMeta(a),r=o.dataset,l=null,r&&r.options&&r instanceof oo&&(l={visible:t.isDatasetVisible(a),index:a,fill:ra(r,a,s),chart:t,axis:o.controller.options.indexAxis,scale:o.vScale,line:r}),o.$filler=l,n.push(l);for(a=0;a<s;++a)l=n[a],l&&!1!==l.fill&&(l.fill=aa(n,a,i.propagate))},beforeDraw(t,e,i){const s="beforeDraw"===i.drawTime,n=t.getSortedVisibleDatasetMetas(),o=t.chartArea;for(let e=n.length-1;e>=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&i.fill&&ua(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;oa(i)&&ua(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;oa(s)&&"beforeDatasetDraw"===i.drawTime&&ua(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const _a=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=t.pointStyleWidth||Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class ya extends $s{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=d(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=Si(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=_a(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,s,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const{itemWidth:p,itemHeight:m}=function(t,e,i,s,n){const o=function(t,e,i,s){let n=t.text;n&&"string"!=typeof n&&(n=n.reduce(((t,e)=>t.length>e.length?t:e)));return e+i.size/2+s.measureText(n).width}(s,t,e,i),a=function(t,e,i){let s=t;"string"!=typeof e.text&&(s=va(e,i));return s}(n,s,e.lineHeight);return{itemWidth:o,itemHeight:a}}(i,e,n,t,s);o>0&&u+m+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:m},d=Math.max(d,p),u+=m+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:n}}=this,o=Oi(n,this.left,this.width);if(this.isHorizontal()){let n=0,a=ft(i,this.left+s,this.right-this.lineWidths[n]);for(const r of e)n!==r.row&&(n=r.row,a=ft(i,this.left+s,this.right-this.lineWidths[n])),r.top+=this.top+t+s,r.left=o.leftForLtr(o.x(a),r.width),a+=r.width+s}else{let n=0,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height);for(const r of e)r.col!==n&&(n=r.col,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height)),r.top=a,r.left+=this.left+s,r.left=o.leftForLtr(o.x(r.left),r.width),a+=r.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Ie(t,this),this._draw(),ze(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:n,labels:o}=t,a=ue.color,r=Oi(t.rtl,this.left,this.width),h=Si(o.font),{padding:c}=o,d=h.size,u=d/2;let f;this.drawTitle(),s.textAlign=r.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=h.string;const{boxWidth:g,boxHeight:p,itemHeight:m}=_a(o,d),x=this.isHorizontal(),b=this._computeTitleHeight();f=x?{x:ft(n,this.left+c,this.right-i[0]),y:this.top+c+b,line:0}:{x:this.left+c,y:ft(n,this.top+b+c,this.bottom-e[0].height),line:0},Ai(this.ctx,t.textDirection);const _=m+c;this.legendItems.forEach(((y,v)=>{s.strokeStyle=y.fontColor,s.fillStyle=y.fontColor;const M=s.measureText(y.text).width,w=r.textAlign(y.textAlign||(y.textAlign=o.textAlign)),k=g+u+M;let S=f.x,P=f.y;r.setWidth(this.width),x?v>0&&S+k+c>this.right&&(P=f.y+=_,f.line++,S=f.x=ft(n,this.left+c,this.right-i[f.line])):v>0&&P+_>this.bottom&&(S=f.x=S+e[f.line].width+c,f.line++,P=f.y=ft(n,this.top+b+c,this.bottom-e[f.line].height));if(function(t,e,i){if(isNaN(g)||g<=0||isNaN(p)||p<0)return;s.save();const n=l(i.lineWidth,1);if(s.fillStyle=l(i.fillStyle,a),s.lineCap=l(i.lineCap,"butt"),s.lineDashOffset=l(i.lineDashOffset,0),s.lineJoin=l(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=l(i.strokeStyle,a),s.setLineDash(l(i.lineDash,[])),o.usePointStyle){const a={radius:p*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},l=r.xPlus(t,g/2);Ee(s,a,l,e+u,o.pointStyleWidth&&g)}else{const o=e+Math.max((d-p)/2,0),a=r.leftForLtr(t,g),l=wi(i.borderRadius);s.beginPath(),Object.values(l).some((t=>0!==t))?He(s,{x:a,y:o,w:g,h:p,radius:l}):s.rect(a,o,g,p),s.fill(),0!==n&&s.stroke()}s.restore()}(r.x(S),P,y),S=gt(w,S+g+u,x?S+k:this.right,t.rtl),function(t,e,i){Ne(s,i.text,t,e+m/2,h,{strikethrough:i.hidden,textAlign:r.textAlign(i.textAlign)})}(r.x(S),P,y),x)f.x+=k+c;else if("string"!=typeof y.text){const t=h.lineHeight;f.y+=va(y,t)+c}else f.y+=_})),Ti(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=Si(e.font),s=ki(e.padding);if(!e.display)return;const n=Oi(t.rtl,this.left,this.width),o=this.ctx,a=e.position,r=i.size/2,l=s.top+r;let h,c=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),h=this.top+l,c=ft(t.align,c,this.right-d);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);h=l+ft(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const u=ft(a,c,c+d);o.textAlign=n.textAlign(ut(a)),o.textBaseline="middle",o.strokeStyle=e.color,o.fillStyle=e.color,o.font=i.string,Ne(o,e.text,u,h,i)}_computeTitleHeight(){const t=this.options.title,e=Si(t.font),i=ki(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(tt(t,this.left,this.right)&&tt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;i<n.length;++i)if(s=n[i],tt(t,s.left,s.left+s.width)&&tt(e,s.top,s.top+s.height))return this.legendItems[i];return null}handleEvent(t){const e=this.options;if(!function(t,e){if(("mousemove"===t||"mouseout"===t)&&(e.onHover||e.onLeave))return!0;if(e.onClick&&("click"===t||"mouseup"===t))return!0;return!1}(t.type,e))return;const i=this._getLegendItemAt(t.x,t.y);if("mousemove"===t.type||"mouseout"===t.type){const o=this._hoveredItem,a=(n=i,null!==(s=o)&&null!==n&&s.datasetIndex===n.datasetIndex&&s.index===n.index);o&&!a&&d(e.onLeave,[t,o,this],this),this._hoveredItem=i,i&&!a&&d(e.onHover,[t,i,this],this)}else i&&d(e.onClick,[t,i,this],this);var s,n}}function va(t,e){return e*(t.text?t.text.length:0)}var Ma={id:"legend",_element:ya,start(t,e,i){const s=t.legend=new ya({ctx:t.ctx,options:i,chart:t});ls.configure(t,s,i),ls.addBox(t,s)},stop(t){ls.removeBox(t,t.legend),delete t.legend},beforeUpdate(t,e,i){const s=t.legend;ls.configure(t,s,i),s.options=i},afterUpdate(t){const e=t.legend;e.buildLabels(),e.adjustHitBoxes()},afterEvent(t,e){e.replay||t.legend.handleEvent(e.event)},defaults:{display:!0,position:"top",align:"center",fullSize:!0,reverse:!1,weight:1e3,onClick(t,e,i){const s=e.datasetIndex,n=i.chart;n.isDatasetVisible(s)?(n.hide(s),e.hidden=!0):(n.show(s),e.hidden=!1)},onHover:null,onLeave:null,labels:{color:t=>t.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o,useBorderRadius:a,borderRadius:r}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const l=t.controller.getStyle(i?0:void 0),h=ki(l.borderWidth);return{text:e[t.index].label,fillStyle:l.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:l.borderCapStyle,lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:(h.width+h.height)/4,strokeStyle:l.borderColor,pointStyle:s||l.pointStyle,rotation:l.rotation,textAlign:n||l.textAlign,borderRadius:a&&(r||l.borderRadius),datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class wa extends $s{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=n(i.text)?i.text.length:1;this._padding=ki(i.padding);const o=s*Si(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=o:this.width=o}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:n,options:o}=this,a=o.align;let r,l,h,c=0;return this.isHorizontal()?(l=ft(a,i,n),h=e+t,r=n-i):("left"===o.position?(l=i+t,h=ft(a,s,e),c=-.5*C):(l=n-t,h=ft(a,e,s),c=.5*C),r=s-e),{titleX:l,titleY:h,maxWidth:r,rotation:c}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=Si(e.font),s=i.lineHeight/2+this._padding.top,{titleX:n,titleY:o,maxWidth:a,rotation:r}=this._drawArgs(s);Ne(t,e.text,0,0,i,{color:e.color,maxWidth:a,rotation:r,textAlign:ut(e.align),textBaseline:"middle",translation:[n,o]})}}var ka={id:"title",_element:wa,start(t,e,i){!function(t,e){const i=new wa({ctx:t.ctx,options:e,chart:t});ls.configure(t,i,e),ls.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;ls.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;ls.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Sa=new WeakMap;var Pa={id:"subtitle",start(t,e,i){const s=new wa({ctx:t.ctx,options:i,chart:t});ls.configure(t,s,i),ls.addBox(t,s),Sa.set(t,s)},stop(t){ls.removeBox(t,Sa.get(t)),Sa.delete(t)},beforeUpdate(t,e,i){const s=Sa.get(t);ls.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Da={average(t){if(!t.length)return!1;let e,i,s=new Set,n=0,o=0;for(e=0,i=t.length;e<i;++e){const i=t[e].element;if(i&&i.hasValue()){const t=i.tooltipPosition();s.add(t.x),n+=t.y,++o}}if(0===o||0===s.size)return!1;return{x:[...s].reduce(((t,e)=>t+e))/s.size,y:n/o}},nearest(t,e){if(!t.length)return!1;let i,s,n,o=e.x,a=e.y,r=Number.POSITIVE_INFINITY;for(i=0,s=t.length;i<s;++i){const s=t[i].element;if(s&&s.hasValue()){const t=q(e,s.getCenterPoint());t<r&&(r=t,n=s)}}if(n){const t=n.tooltipPosition();o=t.x,a=t.y}return{x:o,y:a}}};function Ca(t,e){return e&&(n(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function Oa(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function Aa(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Ta(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=Si(e.bodyFont),h=Si(e.titleFont),c=Si(e.footerFont),d=o.length,f=n.length,g=s.length,p=ki(e.padding);let m=p.height,x=0,b=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(b+=t.beforeBody.length+t.afterBody.length,d&&(m+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),b){m+=g*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(b-g)*l.lineHeight+(b-1)*e.bodySpacing}f&&(m+=e.footerMarginTop+f*c.lineHeight+(f-1)*e.footerSpacing);let _=0;const y=function(t){x=Math.max(x,i.measureText(t).width+_)};return i.save(),i.font=h.string,u(t.title,y),i.font=l.string,u(t.beforeBody.concat(t.afterBody),y),_=e.displayColors?a+2+e.boxPadding:0,u(s,(t=>{u(t.before,y),u(t.lines,y),u(t.after,y)})),_=0,i.font=c.string,u(t.footer,y),i.restore(),x+=p.width,{width:x,height:m}}function La(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function Ea(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return i<s/2?"top":i>t.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||La(t,e,i,s),yAlign:s}}function Ra(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=wi(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:Z(g,0,s.width-e.width),y:Z(p,0,s.height-e.height)}}function Ia(t,e,i){const s=ki(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function za(t){return Ca([],Oa(t))}function Fa(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}const Va={beforeTitle:e,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex<s)return i[e.dataIndex]}return""},afterTitle:e,beforeBody:e,beforeLabel:e,label(t){if(this&&this.options&&"dataset"===this.options.mode)return t.label+": "+t.formattedValue||t.formattedValue;let e=t.dataset.label||"";e&&(e+=": ");const i=t.formattedValue;return s(i)||(e+=i),e},labelColor(t){const e=t.chart.getDatasetMeta(t.datasetIndex).controller.getStyle(t.dataIndex);return{borderColor:e.borderColor,backgroundColor:e.backgroundColor,borderWidth:e.borderWidth,borderDash:e.borderDash,borderDashOffset:e.borderDashOffset,borderRadius:0}},labelTextColor(){return this.options.bodyColor},labelPointStyle(t){const e=t.chart.getDatasetMeta(t.datasetIndex).controller.getStyle(t.dataIndex);return{pointStyle:e.pointStyle,rotation:e.rotation}},afterLabel:e,afterBody:e,beforeFooter:e,footer:e,afterFooter:e};function Ba(t,e,i,s){const n=t[e].call(i,s);return void 0===n?Va[e].call(i,s):n}class Wa extends $s{static positioners=Da;constructor(t){super(),this.opacity=0,this._active=[],this._eventPosition=void 0,this._size=void 0,this._cachedAnimations=void 0,this._tooltipItems=[],this.$animations=void 0,this.$context=void 0,this.chart=t.chart,this.options=t.options,this.dataPoints=void 0,this.title=void 0,this.beforeBody=void 0,this.body=void 0,this.afterBody=void 0,this.footer=void 0,this.xAlign=void 0,this.yAlign=void 0,this.x=void 0,this.y=void 0,this.height=void 0,this.width=void 0,this.caretX=void 0,this.caretY=void 0,this.labelColors=void 0,this.labelPointStyles=void 0,this.labelTextColors=void 0}initialize(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}_resolveAnimations(){const t=this._cachedAnimations;if(t)return t;const e=this.chart,i=this.options.setContext(this.getContext()),s=i.enabled&&e.options.animation&&i.animations,n=new Ts(this.chart,s);return s._cacheable&&(this._cachedAnimations=Object.freeze(n)),n}getContext(){return this.$context||(this.$context=(t=this.chart.getContext(),e=this,i=this._tooltipItems,Ci(t,{tooltip:e,tooltipItems:i,type:"tooltip"})));var t,e,i}getTitle(t,e){const{callbacks:i}=e,s=Ba(i,"beforeTitle",this,t),n=Ba(i,"title",this,t),o=Ba(i,"afterTitle",this,t);let a=[];return a=Ca(a,Oa(s)),a=Ca(a,Oa(n)),a=Ca(a,Oa(o)),a}getBeforeBody(t,e){return za(Ba(e.callbacks,"beforeBody",this,t))}getBody(t,e){const{callbacks:i}=e,s=[];return u(t,(t=>{const e={before:[],lines:[],after:[]},n=Fa(i,t);Ca(e.before,Oa(Ba(n,"beforeLabel",this,t))),Ca(e.lines,Ba(n,"label",this,t)),Ca(e.after,Oa(Ba(n,"afterLabel",this,t))),s.push(e)})),s}getAfterBody(t,e){return za(Ba(e.callbacks,"afterBody",this,t))}getFooter(t,e){const{callbacks:i}=e,s=Ba(i,"beforeFooter",this,t),n=Ba(i,"footer",this,t),o=Ba(i,"afterFooter",this,t);let a=[];return a=Ca(a,Oa(s)),a=Ca(a,Oa(n)),a=Ca(a,Oa(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;a<r;++a)l.push(Aa(this.chart,e[a]));return t.filter&&(l=l.filter(((e,s,n)=>t.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),u(l,(e=>{const i=Fa(t.callbacks,e);s.push(Ba(i,"labelColor",this,e)),n.push(Ba(i,"labelPointStyle",this,e)),o.push(Ba(i,"labelTextColor",this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=Da[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Ta(this,i),a=Object.assign({},t,e),r=Ea(this.chart,i,a),l=Ra(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=wi(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,x,b,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,b=_+o,y=_-o):(p=d+f,m=p+o,b=_-o,y=_+o),x=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(b=u,_=b-o,p=m-o,x=m+o):(b=u+g,_=b+o,p=m+o,x=m-o),y=b),{x1:p,x2:m,x3:x,y1:b,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Oi(i.rtl,this.x,this.width);for(t.x=Ia(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=Si(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r<n;++r)e.fillText(s[r],l.x(t.x),t.y+o.lineHeight/2),t.y+=o.lineHeight+a,r+1===n&&(t.y+=i.titleMarginBottom-a)}}_drawColorBox(t,e,i,s,n){const a=this.labelColors[i],r=this.labelPointStyles[i],{boxHeight:l,boxWidth:h}=n,c=Si(n.bodyFont),d=Ia(this,"left",n),u=s.x(d),f=l<c.lineHeight?(c.lineHeight-l)/2:0,g=e.y+f;if(n.usePointStyle){const e={radius:Math.min(h,l)/2,pointStyle:r.pointStyle,rotation:r.rotation,borderWidth:1},i=s.leftForLtr(u,h)+h/2,o=g+l/2;t.strokeStyle=n.multiKeyBackground,t.fillStyle=n.multiKeyBackground,Le(t,e,i,o),t.strokeStyle=a.borderColor,t.fillStyle=a.backgroundColor,Le(t,e,i,o)}else{t.lineWidth=o(a.borderWidth)?Math.max(...Object.values(a.borderWidth)):a.borderWidth||1,t.strokeStyle=a.borderColor,t.setLineDash(a.borderDash||[]),t.lineDashOffset=a.borderDashOffset||0;const e=s.leftForLtr(u,h),i=s.leftForLtr(s.xPlus(u,1),h-2),r=wi(a.borderRadius);Object.values(r).some((t=>0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,He(t,{x:e,y:g,w:h,h:l,radius:r}),t.fill(),t.stroke(),t.fillStyle=a.backgroundColor,t.beginPath(),He(t,{x:i,y:g+1,w:h-2,h:l-2,radius:r}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,h,l),t.strokeRect(e,g,h,l),t.fillStyle=a.backgroundColor,t.fillRect(i,g+1,h-2,l-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=Si(i.bodyFont);let d=c.lineHeight,f=0;const g=Oi(i.rtl,this.x,this.width),p=function(i){e.fillText(i,g.x(t.x+f),t.y+d/2),t.y+=d+n},m=g.textAlign(o);let x,b,_,y,v,M,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=Ia(this,m,i),e.fillStyle=i.bodyColor,u(this.beforeBody,p),f=a&&"right"!==m?"center"===o?l/2+h:l+2+h:0,y=0,M=s.length;y<M;++y){for(x=s[y],b=this.labelTextColors[y],e.fillStyle=b,u(x.before,p),_=x.lines,a&&_.length&&(this._drawColorBox(e,t,y,g,i),d=Math.max(c.lineHeight,r)),v=0,w=_.length;v<w;++v)p(_[v]),d=c.lineHeight;u(x.after,p)}f=0,d=c.lineHeight,u(this.afterBody,p),t.y-=n}drawFooter(t,e,i){const s=this.footer,n=s.length;let o,a;if(n){const r=Oi(i.rtl,this.x,this.width);for(t.x=Ia(this,i.footerAlign,i),t.y+=i.footerMarginTop,e.textAlign=r.textAlign(i.footerAlign),e.textBaseline="middle",o=Si(i.footerFont),e.fillStyle=i.footerColor,e.font=o.string,a=0;a<n;++a)e.fillText(s[a],r.x(t.x),t.y+o.lineHeight/2),t.y+=o.lineHeight+i.footerSpacing}}drawBackground(t,e,i,s){const{xAlign:n,yAlign:o}=this,{x:a,y:r}=t,{width:l,height:h}=i,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=wi(s.cornerRadius);e.fillStyle=s.backgroundColor,e.strokeStyle=s.borderColor,e.lineWidth=s.borderWidth,e.beginPath(),e.moveTo(a+c,r),"top"===o&&this.drawCaret(t,e,i,s),e.lineTo(a+l-d,r),e.quadraticCurveTo(a+l,r,a+l,r+d),"center"===o&&"right"===n&&this.drawCaret(t,e,i,s),e.lineTo(a+l,r+h-f),e.quadraticCurveTo(a+l,r+h,a+l-f,r+h),"bottom"===o&&this.drawCaret(t,e,i,s),e.lineTo(a+u,r+h),e.quadraticCurveTo(a,r+h,a,r+h-u),"center"===o&&"left"===n&&this.drawCaret(t,e,i,s),e.lineTo(a,r+c),e.quadraticCurveTo(a,r,a+c,r),e.closePath(),e.fill(),s.borderWidth>0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=Da[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Ta(this,t),a=Object.assign({},i,this._size),r=Ea(e,t,a),l=Ra(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}_willRender(){return!!this.opacity}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=ki(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ai(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),Ti(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!f(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!f(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e.filter((t=>this.chart.data.datasets[t.datasetIndex]&&void 0!==this.chart.getDatasetMeta(t.datasetIndex).controller.getParsed(t.index)));const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=Da[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}var Na={id:"tooltip",_element:Wa,positioners:Da,afterInit(t,e,i){i&&(t.tooltip=new Wa({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip;if(e&&e._willRender()){const i={tooltip:e};if(!1===t.notifyPlugins("beforeTooltipDraw",{...i,cancelable:!0}))return;e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i)}},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:Va},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:t=>"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return Tn.register(Un,$o,go,t),Tn.helpers={...Hi},Tn._adapters=In,Tn.Animation=As,Tn.Animations=Ts,Tn.animator=bt,Tn.controllers=nn.controllers.items,Tn.DatasetController=js,Tn.Element=$s,Tn.elements=go,Tn.Interaction=Ki,Tn.layouts=ls,Tn.platforms=Ds,Tn.Scale=tn,Tn.Ticks=ae,Object.assign(Tn,Un,$o,go,t,Ds),Tn.Chart=Tn,"undefined"!=typeof window&&(window.Chart=Tn),Tn})); 14 //# sourceMappingURL=chart.umd.min.js.map -
post-views-counter/tags/1.8.0/blocks/most-viewed-posts/index.asset.php
r3470602 r3734102 1 <?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => ' 68a082639217d4af5888');1 <?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '57f13f02c4751ea3e260'); -
post-views-counter/tags/1.8.0/blocks/most-viewed-posts/index.js
r3470602 r3734102 1 !function(e,t,n,o,r,l){"use strict";var i=function(){return t.createElement(n.Spinner)},a=function(){return t.createElement(n.Notice,{status:"error",isDismissible:!1},o.__("Something went wrong. Try again or refresh the page.","post-views-counter"))};function s(e){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,o)}return n}function u(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach(function(t){p(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function p(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=s(e)||!e)return e;var n =e[Symbol.toPrimitive];if(void 0!==n){var o=n.call(e,t);if("object"!=s(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==s(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function m(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var o,r,l,i,a=[],s=!0,c=!1;try{if(l=(n=n.call(e)).next,0===t);else for(;!(s=(o=l.call(n)).done)&&(a.push(o.value),a.length!==t);s=!0);}catch(u){c=!0,r=u}finally{try{if(!s&&null!=n.return&&(i=n.return(),Object(i)!==i))return}finally{if(c)throw r}}return a}}(e,t)||function(e,t){if(e){if("string"==typeof e)return b(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?b(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function b(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n<t;n++)o[n]=e[n];return o}var v=t.createElement(function(e){var n=e.viewBox,o=void 0===n?"0 0 24 24":n,r=e.children;return t.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:o,width:24,height:24,fill:"currentColor"},r)},{viewBox:"0 0 16 16"},t.createElement("path",{d:"M12 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1ZM6.5 6a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V6ZM2 9a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V9Z"}));e.registerBlockType("post-views-counter/most-viewed-posts",{icon:v,edit:function(e){var s=e.attributes,c=e.setAttributes,b=s.title,v=s.postTypes,w=s.period,f=s.numberOfPosts,d=s.noPostsMessage,y=s.order,h=s.listType,_=s.displayPostViews,g=s.displayPostExcerpt,E=s.displayPostAuthor,C=s.displayPostThumbnail,P=s.thumbnailSize,x=m(t.useState(v||pvcBlockEditorData.postTypesKeys),2),O=x[0],B=x[1];return wp.element.createElement(wp.element.Fragment,null,wp.element.createElement(r.InspectorControls,null,wp.element.createElement(n.PanelBody,{title:o.__("Settings","post-views-counter")},wp.element.createElement(n.TextControl,{__nextHasNoMarginBottom:!0,label:o.__("Title","post-views-counter"),value:b,onChange:function(e){return c({title:e})},help:o.__("Enter empty text to hide title.","post-views-counter")}),wp.element.createElement(n.BaseControl,{__nextHasNoMarginBottom:!0,label:o.__("Post types","post-views-counter")},Object.keys(pvcBlockEditorData.postTypes).map(function(e){return wp.element.createElement(n.CheckboxControl,{key:e,label:pvcBlockEditorData.postTypes[e],checked:O[e],onChange:function(t){var n=u({},v);n[e]=t,B(function(t){return u(u({},t),{},p({},e,!t[e]))}),c({postTypes:n})}})})),wp.element.createElement(n.SelectControl,{__nextHasNoMarginBottom:!0,disabled:1===pvcBlockEditorData.periods.length,label:o.__("Views period","post-views-counter"),value:w,options:pvcBlockEditorData.periods,onChange:function(e){return c({period:e})}}),wp.element.createElement(n.TextControl,{__nextHasNoMarginBottom:!0,label:o.__("Number of posts to show","post-views-counter"),value:f,onChange:function(e){return c({numberOfPosts:Number(e)})}}),wp.element.createElement(n.TextControl,{__nextHasNoMarginBottom:!0,label:o.__("No posts message","post-views-counter"),value:d,onChange:function(e){return c({noPostsMessage:e})}}),wp.element.createElement(n.RadioControl,{label:o.__("Order","post-views-counter"),selected:y,options:[{label:o.__("Ascending","post-views-counter"),value:"asc"},{label:o.__("Descending","post-views-counter"),value:"desc"}],onChange:function(e){return c({order:e})}}),wp.element.createElement(n.RadioControl,{label:o.__("Display style","post-views-counter"),selected:h,options:[{label:o.__("Unordered list","post-views-counter"),value:"unordered"},{label:o.__("Ordered list","post-views-counter"),value:"ordered"}],onChange:function(e){return c({listType:e})}}),wp.element.createElement(n.BaseControl,{__nextHasNoMarginBottom:!0,label:o.__("Display Data","post-views-counter")},wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post views","post-views-counter"),checked:_,onChange:function(e){return c({displayPostViews:e})}}),wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post excerpt","post-views-counter"),checked:g,onChange:function(e){return c({displayPostExcerpt:e})}}),wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post author","post-views-counter"),checked:E,onChange:function(e){return c({displayPostAuthor:e})}}),wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post thumbnail","post-views-counter"),checked:C,onChange:function(e){return c({displayPostThumbnail:e})}}),C&&wp.element.createElement(n.SelectControl,{__nextHasNoMarginBottom:!0,label:o.__("Thumbnail size","post-views-counter"),value:P,options:pvcBlockEditorData.imageSizes,onChange:function(e){return c({thumbnailSize:e})}})))),wp.element.createElement("div",r.useBlockProps(),wp.element.createElement(l,{httpMethod:"POST",block:"post-views-counter/most-viewed-posts",attributes:s,LoadingResponsePlaceholder:i,ErrorResponsePlaceholder:a})))}})}(wp.blocks,wp.element,wp.components,wp.i18n,wp.blockEditor,wp.serverSideRender);1 !function(e,t,n,o,r,l){"use strict";var i=function(){return t.createElement(n.Spinner)},a=function(){return t.createElement(n.Notice,{status:"error",isDismissible:!1},o.__("Something went wrong. Try again or refresh the page.","post-views-counter"))};function s(e){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,o)}return n}function u(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach(function(t){p(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function p(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=s(e)||!e)return e;var n;if("undefined"!=typeof Symbol&&void 0!==(n=e[Symbol.toPrimitive])){var o=n.call(e,t);if("object"!=s(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==s(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function m(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var o,r,l,i,a=[],s=!0,c=!1;try{if(l=(n=n.call(e)).next,0===t);else for(;!(s=(o=l.call(n)).done)&&(a.push(o.value),a.length!==t);s=!0);}catch(u){c=!0,r=u}finally{try{if(!s&&null!=n.return&&(i=n.return(),Object(i)!==i))return}finally{if(c)throw r}}return a}}(e,t)||function(e,t){if(e){if("string"==typeof e)return b(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?b(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function b(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n<t;n++)o[n]=e[n];return o}var f=t.createElement(function(e){var n=e.viewBox,o=void 0===n?"0 0 24 24":n,r=e.children;return t.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:o,width:24,height:24,fill:"currentColor"},r)},{viewBox:"0 0 16 16"},t.createElement("path",{d:"M12 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1ZM6.5 6a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V6ZM2 9a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V9Z"}));e.registerBlockType("post-views-counter/most-viewed-posts",{icon:f,edit:function(e){var s=e.attributes,c=e.setAttributes,b=s.title,f=s.postTypes,v=s.period,w=s.numberOfPosts,d=s.noPostsMessage,y=s.order,h=s.listType,_=s.displayPostViews,g=s.displayPostExcerpt,E=s.displayPostAuthor,C=s.displayPostThumbnail,P=s.thumbnailSize,x=m(t.useState(f||pvcBlockEditorData.postTypesKeys),2),O=x[0],S=x[1];return wp.element.createElement(wp.element.Fragment,null,wp.element.createElement(r.InspectorControls,null,wp.element.createElement(n.PanelBody,{title:o.__("Settings","post-views-counter")},wp.element.createElement(n.TextControl,{__nextHasNoMarginBottom:!0,label:o.__("Title","post-views-counter"),value:b,onChange:function(e){return c({title:e})},help:o.__("Enter empty text to hide title.","post-views-counter")}),wp.element.createElement(n.BaseControl,{__nextHasNoMarginBottom:!0,label:o.__("Post types","post-views-counter")},Object.keys(pvcBlockEditorData.postTypes).map(function(e){return wp.element.createElement(n.CheckboxControl,{key:e,label:pvcBlockEditorData.postTypes[e],checked:O[e],onChange:function(t){var n=u({},f);n[e]=t,S(function(t){return u(u({},t),{},p({},e,!t[e]))}),c({postTypes:n})}})})),wp.element.createElement(n.SelectControl,{__nextHasNoMarginBottom:!0,disabled:1===pvcBlockEditorData.periods.length,label:o.__("Views period","post-views-counter"),value:v,options:pvcBlockEditorData.periods,onChange:function(e){return c({period:e})}}),wp.element.createElement(n.TextControl,{__nextHasNoMarginBottom:!0,label:o.__("Number of posts to show","post-views-counter"),value:w,onChange:function(e){return c({numberOfPosts:Number(e)})}}),wp.element.createElement(n.TextControl,{__nextHasNoMarginBottom:!0,label:o.__("No posts message","post-views-counter"),value:d,onChange:function(e){return c({noPostsMessage:e})}}),wp.element.createElement(n.RadioControl,{label:o.__("Order","post-views-counter"),selected:y,options:[{label:o.__("Ascending","post-views-counter"),value:"asc"},{label:o.__("Descending","post-views-counter"),value:"desc"}],onChange:function(e){return c({order:e})}}),wp.element.createElement(n.RadioControl,{label:o.__("Display style","post-views-counter"),selected:h,options:[{label:o.__("Unordered list","post-views-counter"),value:"unordered"},{label:o.__("Ordered list","post-views-counter"),value:"ordered"}],onChange:function(e){return c({listType:e})}}),wp.element.createElement(n.BaseControl,{__nextHasNoMarginBottom:!0,label:o.__("Display Data","post-views-counter")},wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post views","post-views-counter"),checked:_,onChange:function(e){return c({displayPostViews:e})}}),wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post excerpt","post-views-counter"),checked:g,onChange:function(e){return c({displayPostExcerpt:e})}}),wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post author","post-views-counter"),checked:E,onChange:function(e){return c({displayPostAuthor:e})}}),wp.element.createElement(n.CheckboxControl,{__nextHasNoMarginBottom:!0,label:o.__("Post thumbnail","post-views-counter"),checked:C,onChange:function(e){return c({displayPostThumbnail:e})}}),C&&wp.element.createElement(n.SelectControl,{__nextHasNoMarginBottom:!0,label:o.__("Thumbnail size","post-views-counter"),value:P,options:pvcBlockEditorData.imageSizes,onChange:function(e){return c({thumbnailSize:e})}})))),wp.element.createElement("div",r.useBlockProps(),wp.element.createElement(l,{httpMethod:"POST",block:"post-views-counter/most-viewed-posts",attributes:s,LoadingResponsePlaceholder:i,ErrorResponsePlaceholder:a})))}})}(wp.blocks,wp.element,wp.components,wp.i18n,wp.blockEditor,wp.serverSideRender); -
post-views-counter/tags/1.8.0/css/admin-columns.css
r3452736 r3734102 1 @charset "UTF-8";body{--pvc-columns-primary-color: var(--wp-admin-theme-color, #2271b1);--pvc-columns-success-color: #28a745;--pvc-columns-danger-color: #dc3545;--pvc-columns-warning-color: #ffc107;--pvc-columns-neutral-color: #6 c757d;--pvc-columns-muted-color: #a2a6b0;--pvc-columns-dark-color: #1e1e1e;--pvc-columns-background-color: #fff;--pvc-columns-border-color: #dcdcde;--pvc-columns-hover-color: #f8f9fa}.pvc-modal{display:none}.pvc-modal.is-open{display:block}.pvc-modal__overlay{position:fixed;inset:0;background:#000000b3;display:flex;justify-content:center;align-items:center;z-index:100000}.pvc-modal__container{background-color:var(--pvc-columns-background-color);padding:0;max-width:800px;width:90%;max-height:90vh;border-radius:4px;overflow-y:auto;box-shadow:0 5px 15px #0000004d;position:relative}.pvc-modal__header{display:flex;justify-content:space-between;align-items:center;padding:15px 20px;border-bottom:1px solid var(--pvc-columns-border-color)}.pvc-modal__title{margin:0}.pvc-modal__close{background:transparent;border:none;font-size:28px;font-weight:400;line-height:1;color:var(--pvc-columns-neutral-color);cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease}.pvc-modal__close:hover,.pvc-modal__close:focus{color:var(--pvc-columns-dark-color);outline:none}.pvc-modal__close:before{content:"\d7";margin-top:-4px}.pvc-modal__content{padding:20px}.pvc-modal__content p{margin:0 0 1em;line-height:1.6}.pvc-modal__content ul{margin:0 0 1em 1.25em}.pvc-modal__content ul li{margin-bottom:.5em}.pvc-modal-chart-container{position:relative;height:200px;margin-bottom:20px;background-color:var(--pvc-columns-background-color);border-radius:3px}.pvc-modal-chart-container.loading{opacity:.5;pointer-events:none}.pvc-modal-chart-container .spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);display:none;margin:0;float:none}.pvc-modal-chart-container.loading .spinner{display:block;visibility:visible}.pvc-modal-chart-container canvas{max-width:100%}.pvc-modal-content{padding:15px 20px}.pvc-modal-content-top{margin-bottom:20px}.pvc-modal-content-bottom{padding-top:10px;border-top:1px solid var(--pvc-columns-border-color)}.pvc-modal-count{font-weight:100;font-size:32px;line-height:1}.pvc-modal-summary{display:flex;flex-direction:column;gap:5px}.pvc-modal-views-data{display:flex;align-items:center;gap:10px}.pvc-modal-views-label{font-size:14px;color:var(--pvc-columns-neutral-color);font-weight:500}.pvc-modal-rows-container{max-height:220px;overflow:auto}.pvc-modal-legend,.pvc-modal-data{text-align:left;display:inline-block;vertical-align:top}.pvc-modal-legend{width:25%;padding:0;margin:0 10px 0 0;list-style:none}.pvc-modal-legend li{padding-left:5px;padding-right:5px}.pvc-modal-legend li.inactive,.pvc-modal-legend li.inactive a{color:var(--pvc-columns-muted-color);text-decoration:none}.pvc-modal-data{width:73%;text-align:left;border:1px solid var(--pvc-columns-border-color);border-radius:4px;border-spacing:0;border-collapse:collapse;margin:0}.pvc-modal-data th{border-bottom:1px solid var(--pvc-columns-border-color);padding-left:10px;text-align:left}.pvc-modal-data th+th{text-align:right;padding-right:10px}.pvc-modal-data td{border-bottom:1px solid var(--pvc-columns-border-color);padding-left:10px;text-align:left}.pvc-modal-data td+td{text-align:right;padding-right:10px}.pvc-modal-nav{display:flex;justify-content:space-between;align-items:center}.pvc-modal-nav-prev,.pvc-modal-nav-next{text-decoration:none;font-size:14px;padding:6px 12px;border-radius:3px;transition:background-color .2s ease}.pvc-modal-nav-prev:hover,.pvc-modal-nav-next:hover{background-color:var(--pvc-columns-hover-color)}.pvc-modal-nav-prev.pvc-disabled,.pvc-modal-nav-next.pvc-disabled{opacity:.5;cursor:default;pointer-events:none}.pvc-modal-nav-current{font-weight:600;font-size:14px;color:var(--pvc-columns-dark-color)}.pvc-modal-error{padding:15px 20px;text-align:center;color:var(--pvc-columns-danger-color);font-weight:500;margin:0 0 15px;background-color:#fcf0f1;border:1px solid #f1a0a4;border-radius:3px}.pvc-modal-tabs{display:flex;gap:5px;justify-content:center;border-bottom:1px solid var(--pvc-columns-border-color);padding-bottom:10px;margin-top:12px}.pvc-modal-tab{background:transparent;border:none;border-bottom:2px solid transparent;color:var(--pvc-columns-neutral-color);cursor:default;font-size:14px;font-weight:600;padding:8px 16px;transition:all .2s ease}.pvc-modal-tab.active{color:var(--pvc-columns-primary-color);border-bottom-color:var(--pvc-columns-primary-color);font-weight:600}.pvc-modal-tab:focus{box-shadow:none}.pvc-modal-tab:disabled{cursor:default;pointer-events:none}.pvc-modal-tab:disabled span{opacity:.5}.pvc-modal-tab.pvc-tab-disabled{opacity:.5}.pvc-modal-tab.pvc-pro:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600}@keyframes mmfadeIn{0%{opacity:0}to{opacity:1}}@keyframes mmfadeOut{0%{opacity:1}to{opacity:0}}@keyframes mmslideIn{0%{transform:translateY(-10%)}to{transform:translateY(0)}}@keyframes mmslideOut{0%{transform:translateY(0)}to{transform:translateY(-10%)}}.micromodal-slide{display:none}.micromodal-slide.is-open{display:block}.micromodal-slide[aria-hidden=false] .pvc-modal__overlay{animation:mmfadeIn .3s cubic-bezier(0,0,.2,1)}.micromodal-slide[aria-hidden=false] .pvc-modal__container{animation:mmslideIn .3s cubic-bezier(0,0,.2,1)}.micromodal-slide[aria-hidden=true] .pvc-modal__overlay{animation:mmfadeOut .3s cubic-bezier(0,0,.2,1)}.micromodal-slide[aria-hidden=true] .pvc-modal__container{animation:mmslideOut .3s cubic-bezier(0,0,.2,1)}.micromodal-slide .pvc-modal__container,.micromodal-slide .pvc-modal__overlay{will-change:transform}@media screen and (max-width:768px){.pvc-modal__container{width:95%;max-height:95vh}.pvc-modal__header{padding:15px}.pvc-modal__title{font-size:18px;padding-right:10px}.pvc-modal__content{padding:15px}.pvc-modal-chart-container{height:180px}.pvc-modal-rows-container{max-height:200px;width:100%}.pvc-modal-legend{width:30%}.pvc-modal-data{width:68%}.pvc-modal-content-bottom{padding-top:10px;border-top:1px solid var(--pvc-columns-border-color)}.pvc-modal-nav{flex-direction:column;gap:10px}.pvc-modal-nav-prev,.pvc-modal-nav-next{width:100%;text-align:center}}.pvc-modal-content-middle{margin:16px 0;padding:12px 16px;background:var(--pvc-columns-hover-color);border-radius:3px;border-left:3px solid var(--pvc-columns-primary-color)}.pvc-modal-insights{display:flex;flex-direction:column;gap:8px}.pvc-insight{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;font-size:13px;line-height:1.5;position:relative;padding-left:24px}.pvc-insight:before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);font-size:16px;line-height:1;width:16px;height:16px;display:inline-block;mask-size:cover;background-color:var(--pvc-columns-primary-color)}.pvc-insight-lock:before{mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0ic2l6ZS00Ij4KICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik04IDFhMy41IDMuNSAwIDAgMC0zLjUgMy41VjdBMS41IDEuNSAwIDAgMCAzIDguNXY1QTEuNSAxLjUgMCAwIDAgNC41IDE1aDdhMS41IDEuNSAwIDAgMCAxLjUtMS41di01QTEuNSAxLjUgMCAwIDAgMTEuNSA3VjQuNUEzLjUgMy41IDAgMCAwIDggMVptMiA2VjQuNWEyIDIgMCAxIDAtNCAwVjdoNFoiIGNsaXAtcnVsZT0iZXZlbm9kZCIgLz4KPC9zdmc+Cg==)}.pvc-modal-insights-empty .pvc-insight{padding-left:24px}.pvc-modal-insights-empty .pvc-insight-text{color:var(--pvc-columns-neutral-color);font-style:italic}.pvc-views-header{display:inline-block;width:20px;height:20px}.pvc-views-header svg{vertical-align:middle;color:var(--pvc-columns-primary-color)}.column-post_views{width:74px}.column-traffic_signal{width:2rem;text-align:center!important}.pvc-signal-header,.pvc-views-header{display:inline-block;width:20px;height:20px}.pvc-signal-header svg,.pvc-views-header svg{vertical-align:middle;color:var(--pvc-columns-primary-color)}.pvc-signal{display:inline-block;width:20px;height:20px;position:relative;cursor:default;transition:opacity .2s ease;padding:0}.pvc-signal:hover .pvc-insight{transform:scale(1.2)}.pvc-signal:hover{opacity:.8}.pvc-signal .pvc-insight{display:block;width:100%;height:100%;padding:0;transition:transform .2s ease}.pvc-signal .pvc-insight:before{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-size:16px;line-height:1;width:16px;height:16px;display:inline-block;mask-size:cover}.pvc-insight-silence:before{background-color:var(--pvc-columns-border-color);mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLW1pbnVzLWljb24gbHVjaWRlLW1pbnVzIj48cGF0aCBkPSJNNSAxMmgxNCIvPjwvc3ZnPg==)}.pvc-insight-anomaly:before{background-color:var(--pvc-columns-warning-color);mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWFsZXJ0LXRyaWFuZ2xlLWljb24gbHVjaWRlLWFsZXJ0LXRyaWFuZ2xlIj48cGF0aCBkPSJtMjEuNzMgMTgtOC0xNGEyIDIgMCAwIDAtMy40OCAwbC04IDE0QTIgMiAwIDAgMCA0IDIxaDE2YTIgMiAwIDAgMCAxLjczLTMiLz48cGF0aCBkPSJNMTIgOXY0Ii8+PHBhdGggZD0iTTEyIDE3aC4wMSIvPjwvc3ZnPg==)}@media print{.pvc-modal{display:none!important}}1 @charset "UTF-8";body{--pvc-columns-primary-color: var(--wp-admin-theme-color, #2271b1);--pvc-columns-success-color: #28a745;--pvc-columns-danger-color: #dc3545;--pvc-columns-warning-color: #ffc107;--pvc-columns-neutral-color: #646970;--pvc-columns-muted-color: #a2a6b0;--pvc-columns-dark-color: #1e1e1e;--pvc-columns-background-color: #fff;--pvc-columns-border-color: #dcdcde;--pvc-columns-hover-color: #f8f9fa}.pvc-modal{display:none}.pvc-modal.is-open{display:block}.pvc-modal__overlay{position:fixed;inset:0;background:#000000b3;display:flex;justify-content:center;align-items:center;z-index:100000}.pvc-modal__container{background-color:var(--pvc-columns-background-color);padding:0;max-width:800px;width:90%;max-height:90vh;border-radius:4px;overflow-y:auto;box-shadow:0 5px 15px #0000004d;position:relative}.pvc-modal__header{display:flex;justify-content:space-between;align-items:center;padding:15px 20px;border-bottom:1px solid var(--pvc-columns-border-color)}.pvc-modal__title{margin:0}.pvc-modal__close{background:transparent;border:none;font-size:28px;font-weight:400;line-height:1;color:var(--pvc-columns-neutral-color);cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease}.pvc-modal__close:hover,.pvc-modal__close:focus{color:var(--pvc-columns-dark-color);outline:none}.pvc-modal__close:before{content:"\d7";margin-top:-4px}.pvc-modal__content{padding:20px}.pvc-modal__content p{margin:0 0 1em;line-height:1.6}.pvc-modal__content ul{margin:0 0 1em 1.25em}.pvc-modal__content ul li{margin-bottom:.5em}.pvc-modal-chart-container{position:relative;height:200px;margin-bottom:20px;background-color:var(--pvc-columns-background-color);border-radius:3px}.pvc-modal-chart-container.loading{opacity:.5;pointer-events:none}.pvc-modal-chart-container .spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);display:none;margin:0;float:none}.pvc-modal-chart-container.loading .spinner{display:block;visibility:visible}.pvc-modal-chart-container canvas{max-width:100%}.pvc-modal-status{min-height:1.5em;margin-bottom:10px;color:var(--pvc-columns-neutral-color);font-size:13px;line-height:1.5;text-align:center}.pvc-modal-content{padding:15px 20px}.pvc-modal-content-top{margin-bottom:20px}.pvc-modal-content-bottom{padding-top:10px;border-top:1px solid var(--pvc-columns-border-color)}.pvc-modal-count{font-weight:100;font-size:32px;line-height:1}.pvc-modal-summary{display:flex;flex-direction:column;gap:5px}.pvc-modal-views-data{display:flex;align-items:center;gap:10px}.pvc-modal-views-label{font-size:14px;color:var(--pvc-columns-neutral-color);font-weight:500}.pvc-modal-nav{display:flex;justify-content:space-between;align-items:center}.pvc-modal-nav-prev,.pvc-modal-nav-next{text-decoration:none;font-size:14px;padding:6px 12px;border-radius:3px;transition:background-color .2s ease}.pvc-modal-nav-prev:hover,.pvc-modal-nav-next:hover{background-color:var(--pvc-columns-hover-color)}.pvc-modal-nav-prev.pvc-disabled,.pvc-modal-nav-next.pvc-disabled{opacity:.5;cursor:default;pointer-events:none}.pvc-modal-nav-current{font-weight:600;font-size:14px;color:var(--pvc-columns-dark-color)}.pvc-modal-error{padding:15px 20px;text-align:center;color:var(--pvc-columns-danger-color);font-weight:500;margin:0 0 15px;background-color:#fcf0f1;border:1px solid #f1a0a4;border-radius:3px}.pvc-modal-retry{margin-left:.25em}.pvc-modal-tabs{display:flex;gap:5px;justify-content:center;border-bottom:1px solid var(--pvc-columns-border-color);padding-bottom:10px;margin-top:12px}.pvc-modal-tab{background:transparent;border:none;border-bottom:2px solid transparent;color:var(--pvc-columns-neutral-color);cursor:default;font-size:14px;font-weight:600;padding:8px 16px;transition:all .2s ease}.pvc-modal-tab.active{color:var(--pvc-columns-primary-color);border-bottom-color:var(--pvc-columns-primary-color);font-weight:600}.pvc-modal-tab:focus{box-shadow:none}.pvc-modal-tab:focus-visible{outline:2px solid var(--pvc-columns-primary-color);outline-offset:2px;box-shadow:0 0 0 2px #fff,0 0 0 4px var(--pvc-columns-primary-color)}.pvc-modal-tab:disabled{cursor:default;pointer-events:none}.pvc-modal-tab:disabled span{opacity:.5}.pvc-modal-tab.pvc-tab-disabled{opacity:.5}.pvc-modal-tab.pvc-pro:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600}@keyframes mmfadeIn{0%{opacity:0}to{opacity:1}}@keyframes mmfadeOut{0%{opacity:1}to{opacity:0}}@keyframes mmslideIn{0%{transform:translateY(-10%)}to{transform:translateY(0)}}@keyframes mmslideOut{0%{transform:translateY(0)}to{transform:translateY(-10%)}}.micromodal-slide{display:none}.micromodal-slide.is-open{display:block}.micromodal-slide[aria-hidden=false] .pvc-modal__overlay{animation:mmfadeIn .3s cubic-bezier(0,0,.2,1)}.micromodal-slide[aria-hidden=false] .pvc-modal__container{animation:mmslideIn .3s cubic-bezier(0,0,.2,1)}.micromodal-slide[aria-hidden=true] .pvc-modal__overlay{animation:mmfadeOut .3s cubic-bezier(0,0,.2,1)}.micromodal-slide[aria-hidden=true] .pvc-modal__container{animation:mmslideOut .3s cubic-bezier(0,0,.2,1)}.micromodal-slide .pvc-modal__container,.micromodal-slide .pvc-modal__overlay{will-change:transform}@media screen and (max-width:768px){.pvc-modal__container{width:95%;max-height:95vh}.pvc-modal__header{padding:15px}.pvc-modal__title{font-size:18px;padding-right:10px}.pvc-modal__content{padding:15px}.pvc-modal-chart-container{height:180px}.pvc-modal-content-bottom{padding-top:10px;border-top:1px solid var(--pvc-columns-border-color)}.pvc-modal-nav{flex-direction:column;gap:10px}.pvc-modal-nav-prev,.pvc-modal-nav-next{width:100%;text-align:center}}.pvc-modal-content-middle{margin:16px 0;padding:12px 16px;background:var(--pvc-columns-hover-color);border-radius:3px;border-left:3px solid var(--pvc-columns-primary-color)}.pvc-modal-insights{display:flex;flex-direction:column;gap:8px}.pvc-insight{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;font-size:13px;line-height:1.5;position:relative;padding-left:24px}.pvc-insight:before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);font-size:16px;line-height:1;width:16px;height:16px;display:inline-block;mask-size:cover;background-color:var(--pvc-columns-primary-color)}.pvc-insight-lock:before{mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0ic2l6ZS00Ij4KICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik04IDFhMy41IDMuNSAwIDAgMC0zLjUgMy41VjdBMS41IDEuNSAwIDAgMCAzIDguNXY1QTEuNSAxLjUgMCAwIDAgNC41IDE1aDdhMS41IDEuNSAwIDAgMCAxLjUtMS41di01QTEuNSAxLjUgMCAwIDAgMTEuNSA3VjQuNUEzLjUgMy41IDAgMCAwIDggMVptMiA2VjQuNWEyIDIgMCAxIDAtNCAwVjdoNFoiIGNsaXAtcnVsZT0iZXZlbm9kZCIgLz4KPC9zdmc+Cg==);background-color:var(--pvc-columns-neutral-color)}.pvc-modal-insights-empty .pvc-insight{padding-left:24px}.pvc-modal-insights-empty .pvc-insight-text{color:var(--pvc-columns-neutral-color);font-style:italic}.pvc-views-header,.pvc-signal-header{display:inline-flex;align-items:center;width:auto;height:20px;vertical-align:top}.pvc-views-header svg,.pvc-signal-header svg{flex:0 0 16px;width:16px;height:16px;color:var(--pvc-columns-primary-color)}.pvc-signal-header svg{flex-basis:14px;width:14px;height:14px}@media screen and (max-width:960px){.wp-list-table.fixed .column-title{width:20%}.column-post_views{width:auto;min-width:5em}}[data-pvc-tooltip]{position:relative}[data-pvc-tooltip]:before,[data-pvc-tooltip]:after{position:absolute;bottom:100%;left:50%;z-index:10;box-sizing:border-box;opacity:0;pointer-events:none;transform:translate3d(-50%,0,0);transform-origin:top;backface-visibility:hidden;will-change:transform;transition:all var(--microtip-transition-duration, .18s) var(--microtip-transition-easing, ease-in-out) var(--microtip-transition-delay, 0s)}[data-pvc-tooltip]:before{content:"";width:18px;height:6px;margin-bottom:5px;background:url(data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2236px%22%20height%3D%2212px%22%3E%3Cpath%20fill%3D%22rgba%2817,%2017,%2017,%200.9%29%22%20transform%3D%22rotate%280%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E) no-repeat;background-size:100% auto!important}[data-pvc-tooltip]:after{content:attr(data-pvc-tooltip);width:max-content;max-width:260px;margin-bottom:11px;padding:.5em 1em;border-radius:4px;background:#111111e6;box-sizing:content-box;color:#fff;font-size:var(--microtip-font-size, 13px);font-weight:var(--microtip-font-weight, normal);text-align:left;text-transform:var(--microtip-text-transform, none);white-space:pre-line}[data-pvc-tooltip]:hover:before,[data-pvc-tooltip]:hover:after{opacity:1;pointer-events:auto;transform:translate3d(-50%,-5px,0)}.column-post_views.sortable a,.column-post_views.sorted a{overflow:visible;display:flow-root}.column-post_views a:focus-visible .pvc-views-header:before,.column-post_views a:focus-visible .pvc-views-header:after{opacity:1;transform:translate3d(-50%,-5px,0)}.column-post_views{width:55px}.column-traffic_signal{width:2rem;text-align:center!important}.pvc-signal{display:inline-block;width:20px;height:20px;position:relative;cursor:default;transition:opacity .2s ease;padding:0}.pvc-signal[data-post-id]{cursor:pointer}.pvc-signal:hover .pvc-insight{transform:scale(1.2);opacity:.8}.pvc-signal .pvc-insight{display:block;width:100%;height:100%;padding:0;transition:transform .2s ease}.pvc-signal .pvc-insight:before{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-size:16px;line-height:1;width:16px;height:16px;display:inline-block;mask-size:cover}.pvc-insight-silence:before{background-color:var(--pvc-columns-border-color);mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLW1pbnVzLWljb24gbHVjaWRlLW1pbnVzIj48cGF0aCBkPSJNNSAxMmgxNCIvPjwvc3ZnPg==)}.pvc-insight-anomaly:before{background-color:var(--pvc-columns-warning-color);mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWFsZXJ0LXRyaWFuZ2xlLWljb24gbHVjaWRlLWFsZXJ0LXRyaWFuZ2xlIj48cGF0aCBkPSJtMjEuNzMgMTgtOC0xNGEyIDIgMCAwIDAtMy40OCAwbC04IDE0QTIgMiAwIDAgMCA0IDIxaDE2YTIgMiAwIDAgMCAxLjczLTMiLz48cGF0aCBkPSJNMTIgOXY0Ii8+PHBhdGggZD0iTTEyIDE3aC4wMSIvPjwvc3ZnPg==)}@media print{.pvc-modal{display:none!important}} -
post-views-counter/tags/1.8.0/css/admin-dashboard.css
r3578455 r3734102 1 .pvc- accordion{--pvc-theme-color: var(--wp-admin-theme-color, #2271b1);--pvc-theme-color-rgb: var(--wp-admin-theme-color--rgb, 34, 113, 177);--pvc-primary-color: #6610f2;--pvc-secondary-color: #ffc107;--pvc-border-color: #eee;--pvc-bg-color: #fafafa;--pvc-dark-color: #212529;--pvc-disabled-color: #72777c}#pvc_dashboard .inside{margin:0;padding:0}.pvc-accordion .pvc-accordion-item.pvc-collapsed .pvc-accordion-toggle:before{transform:rotate(180deg)}.pvc-accordion .pvc-accordion-item.pvc-collapsed .pvc-accordion-content{display:none}.pvc-accordion .pvc-accordion-item .pvc-according-header{display:flex;align-items:center;justify-content:space-between}.pvc-accordion .pvc-accordion-item .pvc-accordion-content{padding:11px 12px;border-bottom:1px solid var(--pvc-border-color);height:100%}.pvc-accordion .pvc-accordion-header{display:flex;align-items:center;justify-content:space-between;background-color:var(--pvc-bg-color);border-bottom:1px solid var(--pvc-border-color);position:relative}.pvc-accordion .pvc-accordion-toggle{background-color:var(--pvc-bg-color);border-bottom:1px solid var(--pvc-border-color);cursor:pointer;position:relative;font-size:14px;font-weight:400;line-height:1;margin:0;padding:11px 12px;color:var(--pvc-dark-color);flex-grow:1}.pvc-accordion .pvc-accordion-title{display:inline-block;padding-right:10px}.pvc-accordion .pvc-accordion-actions{position:absolute;top:0;right:0;z-index:1;padding:11px 6px;height:14px;line-height:1;flex-shrink:0;text-decoration:none}.pvc-accordion .pvc-accordion-actions .pvc-accordion-action{width:14px;text-align:center}.pvc-accordion .pvc-accordion-actions .pvc-accordion-action,.pvc-accordion .pvc-accordion-actions .pvc-accordion-action:before{font-size:14px;height:14px;width:14px;color:var(--pvc-disabled-color);display:inline-block;text-decoration:none!important}.pvc-accordion .pvc-accordion-actions .pvc-toggle-indicator:before{color:var(--pvc-disabled-color);content:"\f142";display:inline-block;font-family:dashicons;line-height:1;transform:rotate(0);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-indent:-1px}.pvc-accordion .pvc-tooltip{position:relative}.pvc-accordion .pvc-tooltip-icon{display:inline-block;width:16px;cursor:help}.pvc-accordion .pvc-tooltip-icon:before{color:var(--pvc-disabled-color);content:"\f14c";display:inline-block;font: 16px/1 dashicons;position:absolute;text-decoration:none!important;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;left:0;top:2px}.pvc-dashboard-container{min-height:260px;margin:0 -4px;text-align:center;position:relative;display:flex;flex-direction:column}.pvc-dashboard-container *{box-sizing:border-box}.pvc-dashboard-container.loading{pointer-events:none}.pvc-dashboard-container.loading:after{position:absolute;content:"";display:block;height:100%;width:100%;top:0;left:0;background-color:#fffc;z-index:1;transition:all .2s}.pvc-dashboard-container .spinner{position:absolute;left:50%;top:40%;margin-left:-10px;z-index:10}.pvc-dashboard-container .pvc-date-nav{display:flex;justify-content:space-between;color:var(--pvc-disabled-color);width:100%;margin:6px 0 0}.pvc-dashboard-container .pvc-date-nav .current{color:var(--pvc-dark-color)}.pvc-dashboard-container .pvc-dashboard p.sub{color:var(--pvc-disabled-color);font-size:14px;text-align:left;padding-bottom:3px;border-bottom:1px solid var(--pvc-border-color)}.pvc-dashboard-container .pvc-data-container{min-height:230px}.pvc-dashboard-container .pvc-data-container a{text-decoration:none}.pvc-dashboard-container .pvc-dashboard-message{display:none;text-align:left}.pvc-dashboard-container .pvc-dashboard-message:not(:empty){display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);padding:10px}.pvc-dashboard-container .pvc-dashboard-error{display:flex;flex-direction:column;align-items:center;gap:8px}.pvc-dashboard-container .pvc-dashboard-error .button{white-space:normal}.pvc-dashboard-container .pvc-table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}.pvc-dashboard-container .pvc-table{caption-side:bottom;border-collapse:collapse;width:100%;margin-bottom:1rem;color:inherit;vertical-align:top;border-color:var(--pvc-border-color);text-align:left}.pvc-dashboard-container .pvc-table>thead{vertical-align:bottom;color:var(--pvc-dark-color)}.pvc-dashboard-container .pvc-table>tbody{vertical-align:inherit}.pvc-dashboard-container .pvc-table tbody,.pvc-dashboard-container .pvc-table td,.pvc-dashboard-container .pvc-table tfoot,.pvc-dashboard-container .pvc-table th,.pvc-dashboard-container .pvc-table thead,.pvc-dashboard-container .pvc-table tr{border-color:inherit;border-style:solid;border-width:0}.pvc-dashboard-container .pvc-table th,.pvc-dashboard-container .pvc-table td{text-align:inherit;text-align:-webkit-match-parent}.pvc-dashboard-container .pvc-table th:first-child,.pvc-dashboard-container .pvc-table td:first-child{width:1px;white-space:nowrap}.pvc-dashboard-container .pvc-table th:last-child,.pvc-dashboard-container .pvc-table td:last-child{text-align:right}.pvc-dashboard-container .pvc-table .no-posts :last-child{text-align:left}.pvc-dashboard-container .pvc-table>:not(caption)>*>*{padding:.5rem;background-color:transparent;border-bottom-width:1px;box-shadow:inset 0 0 0 9999px transparent}.pvc-dashboard-container .pvc-table .cn-edit-link{display:none}.pvc-dashboard-container .pvc-table .cn-edit-link:before{content:"(";display:inline-block}.pvc-dashboard-container .pvc-table .cn-edit-link:after{content:")";display:inline-block}.pvc-dashboard-container .pvc-table tr:hover .cn-edit-link{display:inline-block}.pvc-dashboard-content-top,.pvc-dashboard-content-bottom{padding:0 6px}.pvc-dashboard-block{display:flex;justify-content:center;align-items:center;background:var(--pvc-bg-color);color:var(--pvc-disabled-color);font-size:13px;font-style:italic;padding:13px;margin-top:0}.pvc-dashboard-unlock{padding:13px;margin-top:0}.pvc-dashboard-unlock>div{background-color:#f6f7f7;border:1px solid var(--pvc-border-color);padding:13px;border-radius:3px}.pvc-dashboard-unlock .button{margin:3px 0 5px}.pvc-dashboard-unlock h3{font-weight:600!important}.pvc-dashboard-unlock h3:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:var(--pvc-secondary-color);color:#fff;font-weight:600}1 .pvc-metric-toggle,.pvc-reports-legend{display:flex;width:100%;justify-content:center;align-items:center;flex-wrap:wrap;column-gap:12px;row-gap:8px;margin:0 0 15px;padding:0}.pvc-metric-toggle-item,.pvc-reports-legend-item{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--pvc-columns-border-color, #dcdcde);background:transparent;cursor:pointer;padding:5px 9px}.pvc-metric-toggle-item[aria-pressed=false],.pvc-reports-legend-item[aria-pressed=false]{opacity:.55;text-decoration:line-through}.pvc-metric-toggle-item:disabled,.pvc-reports-legend-item:disabled{cursor:not-allowed;opacity:.55;text-decoration:none}.pvc-metric-toggle-item:focus-visible,.pvc-reports-legend-item:focus-visible{outline:2px solid var(--pvc-columns-primary-color, var(--wp-admin-theme-color, #2271b1));outline-offset:2px}.pvc-metric-toggle-swatch,.pvc-reports-legend-swatch{display:inline-block;width:18px;height:0;border-top-width:2px;border-top-style:solid}.pvc-metric-toggle-swatch-views,.pvc-reports-legend-swatch-views{border-top-style:solid;border-top-color:var(--pvc-metric-views-color, var(--pvc-columns-primary-color, var(--wp-admin-theme-color, #2271b1)))}.pvc-metric-toggle-swatch-visits,.pvc-reports-legend-swatch-visits{border-top-style:dashed;border-top-color:var(--pvc-metric-visits-color, rgb(116, 72, 157))}.pvc-metric-toggle-swatch-circle{width:8px;height:8px;border:0;border-radius:50%}.pvc-accordion{--pvc-theme-color: var(--wp-admin-theme-color, #2271b1);--pvc-theme-color-rgb: var(--wp-admin-theme-color--rgb, 34, 113, 177);--pvc-primary-color: #6610f2;--pvc-secondary-color: #ffc107;--pvc-border-color: #eee;--pvc-bg-color: #fafafa;--pvc-dark-color: #212529;--pvc-disabled-color: #72777c}#pvc_dashboard .inside{margin:0;padding:0}.pvc-accordion .pvc-accordion-item.pvc-collapsed .pvc-accordion-toggle:before{transform:rotate(180deg)}.pvc-accordion .pvc-accordion-item.pvc-collapsed .pvc-accordion-content{display:none}.pvc-accordion .pvc-accordion-item .pvc-according-header{display:flex;align-items:center;justify-content:space-between}.pvc-accordion .pvc-accordion-item .pvc-accordion-content{padding:11px 12px;border-bottom:1px solid var(--pvc-border-color);height:100%}.pvc-accordion .pvc-accordion-header{display:flex;align-items:center;justify-content:space-between;background-color:var(--pvc-bg-color);border-bottom:1px solid var(--pvc-border-color);position:relative}.pvc-accordion .pvc-accordion-toggle{background-color:var(--pvc-bg-color);border-bottom:1px solid var(--pvc-border-color);cursor:pointer;position:relative;font-size:14px;font-weight:400;line-height:1;margin:0;padding:11px 12px;color:var(--pvc-dark-color);flex-grow:1}.pvc-accordion .pvc-accordion-title{display:inline-block;padding-right:10px}.pvc-accordion .pvc-accordion-actions{position:absolute;top:0;right:0;z-index:1;padding:11px 6px;height:14px;line-height:1;flex-shrink:0;text-decoration:none}.pvc-accordion .pvc-accordion-actions .pvc-accordion-action{width:14px;text-align:center}.pvc-accordion .pvc-accordion-actions .pvc-accordion-action,.pvc-accordion .pvc-accordion-actions .pvc-accordion-action:before{font-size:14px;height:14px;width:14px;color:var(--pvc-disabled-color);display:inline-block;text-decoration:none!important}.pvc-accordion .pvc-accordion-actions .pvc-toggle-indicator:before{color:var(--pvc-disabled-color);content:"\f142";display:inline-block;font-family:dashicons;line-height:1;transform:rotate(0);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-indent:-1px}.pvc-accordion .pvc-tooltip{position:relative}.pvc-accordion .pvc-tooltip-icon{display:inline-block;width:16px;cursor:help}.pvc-accordion .pvc-tooltip-icon:before{color:var(--pvc-disabled-color);content:"\f14c";display:inline-block;font: 16px/1 dashicons;position:absolute;text-decoration:none!important;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;left:0;top:2px}.pvc-dashboard-container{min-height:260px;margin:0 -4px;text-align:center;position:relative;display:flex;flex-direction:column}.pvc-dashboard-container *{box-sizing:border-box}.pvc-dashboard-container.loading{pointer-events:none}.pvc-dashboard-container.loading:after{position:absolute;content:"";display:block;height:100%;width:100%;top:0;left:0;background-color:#fffc;z-index:1;transition:all .2s}.pvc-dashboard-container .spinner{position:absolute;left:50%;top:40%;margin-left:-10px;z-index:10}.pvc-dashboard-container .pvc-date-nav{display:flex;justify-content:space-between;color:var(--pvc-disabled-color);width:100%;margin:6px 0 0}.pvc-dashboard-container .pvc-date-nav .current{color:var(--pvc-dark-color)}.pvc-dashboard-container .pvc-dashboard p.sub{color:var(--pvc-disabled-color);font-size:14px;text-align:left;padding-bottom:3px;border-bottom:1px solid var(--pvc-border-color)}.pvc-dashboard-container .pvc-data-container{min-height:230px}.pvc-dashboard-container .pvc-data-container a{text-decoration:none}.pvc-dashboard-container.pvc-dashboard-container-chart .pvc-data-container{min-height:0;margin:10px 0}.pvc-dashboard-container .pvc-chart-wrapper{position:relative;width:100%;height:170px}.pvc-dashboard-container .pvc-chart-wrapper canvas{display:block}.pvc-dashboard-container .pvc-dashboard-metric-controls{padding:0 6px}.pvc-dashboard-container .pvc-dashboard-metrics{margin:0}.pvc-dashboard-container .pvc-dashboard-legend{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;font-weight:400;column-gap:10px;row-gap:4px}.pvc-dashboard-container .pvc-dashboard-legend .pvc-metric-toggle-item{border:0;padding:2px 0;color:inherit;font:inherit;line-height:1.4}.pvc-dashboard-container .pvc-dashboard-visits-unavailable{margin:8px 0 0;color:var(--pvc-disabled-color);font-size:12px}.pvc-dashboard-container .pvc-dashboard-visits-unavailable{margin:0 0 10px}.pvc-dashboard-container .pvc-dashboard-message{display:none;text-align:left}.pvc-dashboard-container .pvc-dashboard-message:not(:empty){display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);padding:10px}.pvc-dashboard-container .pvc-dashboard-error{display:flex;flex-direction:column;align-items:center;gap:8px}.pvc-dashboard-container .pvc-dashboard-error .button{white-space:normal}.pvc-dashboard-container .pvc-table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}.pvc-dashboard-container .pvc-table{caption-side:bottom;border-collapse:collapse;width:100%;margin-bottom:1rem;color:inherit;vertical-align:top;border-color:var(--pvc-border-color);text-align:left}.pvc-dashboard-container .pvc-table>thead{vertical-align:bottom;color:var(--pvc-dark-color)}.pvc-dashboard-container .pvc-table>tbody{vertical-align:inherit}.pvc-dashboard-container .pvc-table tbody,.pvc-dashboard-container .pvc-table td,.pvc-dashboard-container .pvc-table tfoot,.pvc-dashboard-container .pvc-table th,.pvc-dashboard-container .pvc-table thead,.pvc-dashboard-container .pvc-table tr{border-color:inherit;border-style:solid;border-width:0}.pvc-dashboard-container .pvc-table th,.pvc-dashboard-container .pvc-table td{text-align:inherit;text-align:-webkit-match-parent}.pvc-dashboard-container .pvc-table th:first-child,.pvc-dashboard-container .pvc-table td:first-child{width:1px;white-space:nowrap}.pvc-dashboard-container .pvc-table th:last-child,.pvc-dashboard-container .pvc-table td:last-child{text-align:right}.pvc-dashboard-container .pvc-table .no-posts :last-child{text-align:left}.pvc-dashboard-container .pvc-table>:not(caption)>*>*{padding:.5rem;background-color:transparent;border-bottom-width:1px;box-shadow:inset 0 0 0 9999px transparent}.pvc-dashboard-container .pvc-table .cn-edit-link{display:none}.pvc-dashboard-container .pvc-table .cn-edit-link:before{content:"(";display:inline-block}.pvc-dashboard-container .pvc-table .cn-edit-link:after{content:")";display:inline-block}.pvc-dashboard-container .pvc-table tr:hover .cn-edit-link{display:inline-block}.pvc-dashboard-content-top{padding:0 6px}.pvc-dashboard-headline{--pvc-dashboard-dark-color: #1e1e1e;--pvc-dashboard-neutral-color: #646970;display:flex;justify-content:space-between;width:100%;margin-bottom:6px}.pvc-dashboard-headline .pvc-summary{display:flex;align-items:center}.pvc-dashboard-headline .pvc-summary>*{opacity:1;transition:opacity .2s}.pvc-dashboard-headline .pvc-data-count{font-size:18px;font-weight:600;display:inline-block;color:var(--pvc-dashboard-dark-color)}.pvc-dashboard-headline .pvc-date-select{margin-left:auto;opacity:.7;transition:opacity .2s}.pvc-dashboard-headline .pvc-date-select:hover,.pvc-dashboard-headline .pvc-date-select:focus{opacity:1}.pvc-dashboard-headline .pvc-date-select .button{transition:border .05s ease-in-out,background .05s ease-in-out,color .05s ease-in-out}.pvc-dashboard-headline .pvc-date-select .button:not(:focus){outline:0}.pvc-dashboard-headline .pvc-date-select .button:disabled{color:var(--pvc-dashboard-neutral-color)!important;cursor:default}.pvc-dashboard-headline .pvc-date-select .button:disabled span{opacity:.5}.pvc-dashboard-content-bottom{padding:0 6px}.pvc-dashboard-block{display:flex;justify-content:center;align-items:center;background:var(--pvc-bg-color);color:var(--pvc-disabled-color);font-size:13px;font-style:italic;padding:13px;margin-top:0}.pvc-dashboard-unlock{padding:13px;margin-top:0}.pvc-dashboard-unlock>div{background-color:#f6f7f7;border:1px solid var(--pvc-border-color);padding:13px;border-radius:3px}.pvc-dashboard-unlock .button{margin:3px 0 5px}.pvc-dashboard-unlock h3{font-weight:600!important}.pvc-dashboard-unlock h3:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:var(--pvc-secondary-color);color:#fff;font-weight:600}.pvc-widget-insights{margin:12px 6px 4px;padding:4px 12px;background:#f8f9fa;border-left:3px solid var(--pvc-theme-color);border-radius:3px;font-size:13px;line-height:1.5;text-align:left;color:#1e1e1e}.pvc-widget-insights[hidden]{display:none}.pvc-widget-insights .pvc-widget-insight{position:relative;margin:6px 0;padding-left:24px;color:#646970}.pvc-widget-insights .pvc-widget-insight:before{content:"";position:absolute;left:0;top:2px;width:16px;height:16px;mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWluZm8taWNvbiBsdWNpZGUtaW5mbyI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48cGF0aCBkPSJNMTIgMTZ2LTQiLz48cGF0aCBkPSJNMTIgOGguMDEiLz48L3N2Zz4=);mask-size:cover;background-color:#6c757d}.pvc-widget-insights .pvc-widget-insight-up:before{mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXRyZW5kaW5nLXVwLWljb24gbHVjaWRlLXRyZW5kaW5nLXVwIj48cGF0aCBkPSJNMTYgN2g2djYiLz48cGF0aCBkPSJtMjIgNy04LjUgOC41LTUtNUwyIDE3Ii8+PC9zdmc+);background-color:#28a745}.pvc-widget-insights .pvc-widget-insight-down:before{mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXRyZW5kaW5nLWRvd24taWNvbiBsdWNpZGUtdHJlbmRpbmctZG93biI+PHBhdGggZD0iTTE2IDE3aDZ2LTYiLz48cGF0aCBkPSJtMjIgMTctOC41LTguNS01IDVMMiA3Ii8+PC9zdmc+);background-color:#dc3545}.pvc-widget-insights .pvc-widget-insight-locked:before{mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0ic2l6ZS00Ij4KICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik04IDFhMy41IDMuNSAwIDAgMC0zLjUgMy41VjdBMS41IDEuNSAwIDAgMCAzIDguNXY1QTEuNSAxLjUgMCAwIDAgNC41IDE1aDdhMS41IDEuNSAwIDAgMCAxLjUtMS41di01QTEuNSAxLjUgMCAwIDAgMTEuNSA3VjQuNUEzLjUgMy41IDAgMCAwIDggMVptMiA2VjQuNWEyIDIgMCAxIDAtNCAwVjdoNFoiIGNsaXAtcnVsZT0iZXZlbm9kZCIgLz4KPC9zdmc+Cg==)} -
post-views-counter/tags/1.8.0/css/admin-post.css
r3452736 r3734102 1 #misc-publishing-actions #post-views #post-views-display:before{display:inline-block;font:400 20px/1 dashicons;left:-1px;padding:0 2px 0 0;position:relative;text-decoration:none!important;vertical-align:top;color:#888;content:"\f185";top:-1px} .edit-php .widefat th#post_views{width:74px}.edit-php .widefat th.column-post_views .dashicons,.edit-php .widefat th.column-post_views .dashicons:before{font-size:1.1em;vertical-align:middle}.edit-php .widefat th .dash-title{display:none}.edit-php .widefat td .dashicons,.edit-php .widefat td .dashicons:before{font-size:1.1em}.edit-php .metabox-prefs .dash-icon{display:none}.edit-php #inline-edit-post_views input{width:auto}.upload-php .widefat .dash-title{display:none}1 #misc-publishing-actions #post-views #post-views-display:before{display:inline-block;font:400 20px/1 dashicons;left:-1px;padding:0 2px 0 0;position:relative;text-decoration:none!important;vertical-align:top;color:#888;content:"\f185";top:-1px}#misc-publishing-actions #post-views .pvc-editor-counter-field{margin:8px 0}#misc-publishing-actions #post-views .pvc-editor-counter-field label{display:block;margin-bottom:4px}#misc-publishing-actions #post-views .pvc-editor-counter-field input[type=number]{width:100%;max-width:12em}.edit-php .widefat th#post_views{width:74px}.edit-php .widefat th.column-post_views .dashicons,.edit-php .widefat th.column-post_views .dashicons:before{font-size:1.1em;vertical-align:middle}.edit-php .widefat th .dash-title{display:none}.edit-php .widefat td .dashicons,.edit-php .widefat td .dashicons:before{font-size:1.1em}.edit-php .metabox-prefs .dash-icon{display:none}.edit-php #inline-edit-post_views input{width:auto}.upload-php .widefat .dash-title{display:none} -
post-views-counter/tags/1.8.0/css/admin-settings.css
r3578455 r3734102 2 2 * Pico CSS ✨ v2.1.1 (https://picocss.com) 3 3 * Copyright 2019-2025 - Licensed under MIT 4 */:root,:host{--pvc-font-family-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--pvc-font-family-sans-serif: system-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, Helvetica, Arial, "Helvetica Neue", sans-serif, var(--pvc-font-family-emoji);--pvc-font-family-monospace: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace, var(--pvc-font-family-emoji);--pvc-font-family: var(--pvc-font-family-sans-serif);--pvc-line-height: 1.5;--pvc-font-weight: 400;--pvc-font-size: 100%;--pvc-text-underline-offset: .1rem;--pvc-border-radius: .25rem;--pvc-border-width: .0625rem;--pvc-outline-width: .125rem;--pvc-transition: .2s ease-in-out;--pvc-spacing: 1rem;--pvc-group-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-primary-focus);--pvc-group-box-shadow-focus-with-input: 0 0 0 .0625rem var(--pvc-form-element-border-color);--pvc-icon-checkbox: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--pvc-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-date: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--pvc-icon-time: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--pvc-icon-loading: url("data:image/svg+xml,%3Csvg fill='none' height='24' width='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cstyle%3E g %7B animation: rotate 2s linear infinite; transform-origin: center center; %7D circle %7B stroke-dasharray: 75,100; stroke-dashoffset: -5; animation: dash 1.5s ease-in-out infinite; stroke-linecap: round; %7D @keyframes rotate %7B 0%25 %7B transform: rotate(0deg); %7D 100%25 %7B transform: rotate(360deg); %7D %7D @keyframes dash %7B 0%25 %7B stroke-dasharray: 1,100; stroke-dashoffset: 0; %7D 50%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -17.5; %7D 100%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -62; %7D %7D %3C/style%3E%3Cg%3E%3Ccircle cx='12' cy='12' r='10' fill='none' stroke='rgb(136, 145, 164)' stroke-width='4' /%3E%3C/g%3E%3C/svg%3E")}@media(min-width:576px){:root,:host{--pvc-font-size: 106.25%}}@media(min-width:768px){:root,:host{--pvc-font-size: 112.5%}}@media(min-width:1024px){:root,:host{--pvc-font-size: 118.75%}}@media(min-width:1280px){:root,:host{--pvc-font-size: 125%}}@media(min-width:1536px){:root,:host{--pvc-font-size: 131.25%}}a,a.secondary,a.contrast{--pvc-text-decoration: underline}pre,code,kbd,samp{--pvc-font-family: var(--pvc-font-family-monospace)}kbd{--pvc-font-weight: bolder}input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:where(select,textarea){--pvc-outline-width: .0625rem}[type=search]{--pvc-border-radius: 5rem}[type=checkbox],[type=radio]{--pvc-border-width: .125rem}[type=checkbox][role=switch]{--pvc-border-width: .1875rem}[role=search]{--pvc-border-radius: 5rem}[role=search]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus),[role=group]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus){--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-secondary-focus)}[role=search]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus),[role=group]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus){--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-contrast-focus)}[role=search] button,[role=search] [type=submit],[role=search] [type=button],[role=search] [role=button],[role=group] button,[role=group] [type=submit],[role=group] [type=button],[role=group] [role=button]{--pvc-form-element-spacing-horizontal: 2rem}.pvc-settings-form [aria-busy=true]:not(input,select,textarea):is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before{filter:brightness(0) invert(1)}[data-theme=light],:root:not([data-theme=dark]),:host(:not([data-theme=dark])){color-scheme:light;--pvc-background-color: #fff;--pvc-color: #373c44;--pvc-text-selection-color: rgba(2, 154, 232, .25);--pvc-muted-color: #646b79;--pvc-muted-border-color: rgb(231, 234, 239.5);--pvc-primary: #0172ad;--pvc-primary-background: #0172ad;--pvc-primary-border: var(--pvc-primary-background);--pvc-primary-underline: rgba(1, 114, 173, .5);--pvc-primary-hover: #015887;--pvc-primary-hover-background: #02659a;--pvc-primary-hover-border: var(--pvc-primary-hover-background);--pvc-primary-hover-underline: var(--pvc-primary-hover);--pvc-primary-focus: rgba(2, 154, 232, .5);--pvc-primary-inverse: #fff;--pvc-secondary: #5d6b89;--pvc-secondary-background: #525f7a;--pvc-secondary-border: var(--pvc-secondary-background);--pvc-secondary-underline: rgba(93, 107, 137, .5);--pvc-secondary-hover: #48536b;--pvc-secondary-hover-background: #48536b;--pvc-secondary-hover-border: var(--pvc-secondary-hover-background);--pvc-secondary-hover-underline: var(--pvc-secondary-hover);--pvc-secondary-focus: rgba(93, 107, 137, .25);--pvc-secondary-inverse: #fff;--pvc-contrast: #181c25;--pvc-contrast-background: #181c25;--pvc-contrast-border: var(--pvc-contrast-background);--pvc-contrast-underline: rgba(24, 28, 37, .5);--pvc-contrast-hover: #000;--pvc-contrast-hover-background: #000;--pvc-contrast-hover-border: var(--pvc-contrast-hover-background);--pvc-contrast-hover-underline: var(--pvc-secondary-hover);--pvc-contrast-focus: rgba(93, 107, 137, .25);--pvc-contrast-inverse: #fff;--pvc-box-shadow: .0145rem .029rem .174rem rgba(129, 145, 181, .01698), .0335rem .067rem .402rem rgba(129, 145, 181, .024), .0625rem .125rem .75rem rgba(129, 145, 181, .03), .1125rem .225rem 1.35rem rgba(129, 145, 181, .036), .2085rem .417rem 2.502rem rgba(129, 145, 181, .04302), .5rem 1rem 6rem rgba(129, 145, 181, .06), 0 0 0 .0625rem rgba(129, 145, 181, .015);--pvc-code-background-color: rgb(243, 244.5, 246.75);--pvc-code-color: #646b79;--pvc-code-kbd-background-color: var(--pvc-color);--pvc-code-kbd-color: var(--pvc-background-color);--pvc-form-element-background-color: rgb(251, 251.5, 252.25);--pvc-form-element-selected-background-color: #dfe3eb;--pvc-form-element-border-color: #cfd5e2;--pvc-form-element-color: #23262c;--pvc-form-element-placeholder-color: var(--pvc-muted-color);--pvc-form-element-active-background-color: #fff;--pvc-form-element-active-border-color: var(--pvc-primary-border);--pvc-form-element-focus-color: var(--pvc-primary-border);--pvc-form-element-disabled-opacity: .5;--pvc-form-element-invalid-border-color: rgb(183.5, 105.5, 106.5);--pvc-form-element-invalid-active-border-color: rgb(200.25, 79.25, 72.25);--pvc-form-element-invalid-focus-color: var(--pvc-form-element-invalid-active-border-color);--pvc-form-element-valid-border-color: rgb(76, 154.5, 137.5);--pvc-form-element-valid-active-border-color: rgb(39, 152.75, 118.75);--pvc-form-element-valid-focus-color: var(--pvc-form-element-valid-active-border-color);--pvc-switch-background-color: #bfc7d9;--pvc-switch-checked-background-color: var(--pvc-primary-background);--pvc-switch-color: #fff;--pvc-switch-thumb-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-range-border-color: #dfe3eb;--pvc-range-active-border-color: #bfc7d9;--pvc-range-thumb-border-color: var(--pvc-background-color);--pvc-range-thumb-color: var(--pvc-secondary-background);--pvc-range-thumb-active-color: var(--pvc-primary-background);--pvc-loading-spinner-opacity: .5;--pvc-icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(76, 154.5, 137.5)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(200.25, 79.25, 72.25)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}[data-theme=light] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:root:not([data-theme=dark]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:host(:not([data-theme=dark])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pvc-form-element-focus-color: var(--pvc-primary-focus)}@media only screen and (prefers-color-scheme:dark){:root:not([data-theme]),:host(:not([data-theme])){color-scheme:dark;--pvc-background-color: rgb(19, 22.5, 30.5);--pvc-color: #c2c7d0;--pvc-text-selection-color: rgba(1, 170, 255, .1875);--pvc-muted-color: #7b8495;--pvc-muted-border-color: #202632;--pvc-primary: #01aaff;--pvc-primary-background: #0172ad;--pvc-primary-border: var(--pvc-primary-background);--pvc-primary-underline: rgba(1, 170, 255, .5);--pvc-primary-hover: #79c0ff;--pvc-primary-hover-background: #017fc0;--pvc-primary-hover-border: var(--pvc-primary-hover-background);--pvc-primary-hover-underline: var(--pvc-primary-hover);--pvc-primary-focus: rgba(1, 170, 255, .375);--pvc-primary-inverse: #fff;--pvc-secondary: #969eaf;--pvc-secondary-background: #525f7a;--pvc-secondary-border: var(--pvc-secondary-background);--pvc-secondary-underline: rgba(150, 158, 175, .5);--pvc-secondary-hover: #b3b9c5;--pvc-secondary-hover-background: #5d6b89;--pvc-secondary-hover-border: var(--pvc-secondary-hover-background);--pvc-secondary-hover-underline: var(--pvc-secondary-hover);--pvc-secondary-focus: rgba(144, 158, 190, .25);--pvc-secondary-inverse: #fff;--pvc-contrast: #dfe3eb;--pvc-contrast-background: #eff1f4;--pvc-contrast-border: var(--pvc-contrast-background);--pvc-contrast-underline: rgba(223, 227, 235, .5);--pvc-contrast-hover: #fff;--pvc-contrast-hover-background: #fff;--pvc-contrast-hover-border: var(--pvc-contrast-hover-background);--pvc-contrast-hover-underline: var(--pvc-contrast-hover);--pvc-contrast-focus: rgba(207, 213, 226, .25);--pvc-contrast-inverse: #000;--pvc-box-shadow: .0145rem .029rem .174rem rgba(7, 8.5, 12, .01698), .0335rem .067rem .402rem rgba(7, 8.5, 12, .024), .0625rem .125rem .75rem rgba(7, 8.5, 12, .03), .1125rem .225rem 1.35rem rgba(7, 8.5, 12, .036), .2085rem .417rem 2.502rem rgba(7, 8.5, 12, .04302), .5rem 1rem 6rem rgba(7, 8.5, 12, .06), 0 0 0 .0625rem rgba(7, 8.5, 12, .015);--pvc-code-background-color: rgb(26, 30.5, 40.25);--pvc-code-color: #8891a4;--pvc-code-kbd-background-color: var(--pvc-color);--pvc-code-kbd-color: var(--pvc-background-color);--pvc-form-element-background-color: rgb(28, 33, 43.5);--pvc-form-element-selected-background-color: #2a3140;--pvc-form-element-border-color: #2a3140;--pvc-form-element-color: #e0e3e7;--pvc-form-element-placeholder-color: #8891a4;--pvc-form-element-active-background-color: rgb(26, 30.5, 40.25);--pvc-form-element-active-border-color: var(--pvc-primary-border);--pvc-form-element-focus-color: var(--pvc-primary-border);--pvc-form-element-disabled-opacity: .5;--pvc-form-element-invalid-border-color: rgb(149.5, 74, 80);--pvc-form-element-invalid-active-border-color: rgb(183.25, 63.5, 59);--pvc-form-element-invalid-focus-color: var(--pvc-form-element-invalid-active-border-color);--pvc-form-element-valid-border-color: #2a7b6f;--pvc-form-element-valid-active-border-color: rgb(22, 137, 105.5);--pvc-form-element-valid-focus-color: var(--pvc-form-element-valid-active-border-color);--pvc-switch-background-color: #333c4e;--pvc-switch-checked-background-color: var(--pvc-primary-background);--pvc-switch-color: #fff;--pvc-switch-thumb-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-range-border-color: #202632;--pvc-range-active-border-color: #2a3140;--pvc-range-thumb-border-color: var(--pvc-background-color);--pvc-range-thumb-color: var(--pvc-secondary-background);--pvc-range-thumb-active-color: var(--pvc-primary-background);--pvc-loading-spinner-opacity: .5;--pvc-icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}:root:not([data-theme]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:host(:not([data-theme])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pvc-form-element-focus-color: var(--pvc-primary-focus)}:root:not([data-theme]) .pvc-settings-form [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before,:host(:not([data-theme])) .pvc-settings-form [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before{filter:brightness(0)}}[data-theme=dark]{color-scheme:dark;--pvc-background-color: rgb(19, 22.5, 30.5);--pvc-color: #c2c7d0;--pvc-text-selection-color: rgba(1, 170, 255, .1875);--pvc-muted-color: #7b8495;--pvc-muted-border-color: #202632;--pvc-primary: #01aaff;--pvc-primary-background: #0172ad;--pvc-primary-border: var(--pvc-primary-background);--pvc-primary-underline: rgba(1, 170, 255, .5);--pvc-primary-hover: #79c0ff;--pvc-primary-hover-background: #017fc0;--pvc-primary-hover-border: var(--pvc-primary-hover-background);--pvc-primary-hover-underline: var(--pvc-primary-hover);--pvc-primary-focus: rgba(1, 170, 255, .375);--pvc-primary-inverse: #fff;--pvc-secondary: #969eaf;--pvc-secondary-background: #525f7a;--pvc-secondary-border: var(--pvc-secondary-background);--pvc-secondary-underline: rgba(150, 158, 175, .5);--pvc-secondary-hover: #b3b9c5;--pvc-secondary-hover-background: #5d6b89;--pvc-secondary-hover-border: var(--pvc-secondary-hover-background);--pvc-secondary-hover-underline: var(--pvc-secondary-hover);--pvc-secondary-focus: rgba(144, 158, 190, .25);--pvc-secondary-inverse: #fff;--pvc-contrast: #dfe3eb;--pvc-contrast-background: #eff1f4;--pvc-contrast-border: var(--pvc-contrast-background);--pvc-contrast-underline: rgba(223, 227, 235, .5);--pvc-contrast-hover: #fff;--pvc-contrast-hover-background: #fff;--pvc-contrast-hover-border: var(--pvc-contrast-hover-background);--pvc-contrast-hover-underline: var(--pvc-contrast-hover);--pvc-contrast-focus: rgba(207, 213, 226, .25);--pvc-contrast-inverse: #000;--pvc-box-shadow: .0145rem .029rem .174rem rgba(7, 8.5, 12, .01698), .0335rem .067rem .402rem rgba(7, 8.5, 12, .024), .0625rem .125rem .75rem rgba(7, 8.5, 12, .03), .1125rem .225rem 1.35rem rgba(7, 8.5, 12, .036), .2085rem .417rem 2.502rem rgba(7, 8.5, 12, .04302), .5rem 1rem 6rem rgba(7, 8.5, 12, .06), 0 0 0 .0625rem rgba(7, 8.5, 12, .015);--pvc-code-background-color: rgb(26, 30.5, 40.25);--pvc-code-color: #8891a4;--pvc-code-kbd-background-color: var(--pvc-color);--pvc-code-kbd-color: var(--pvc-background-color);--pvc-form-element-background-color: rgb(28, 33, 43.5);--pvc-form-element-selected-background-color: #2a3140;--pvc-form-element-border-color: #2a3140;--pvc-form-element-color: #e0e3e7;--pvc-form-element-placeholder-color: #8891a4;--pvc-form-element-active-background-color: rgb(26, 30.5, 40.25);--pvc-form-element-active-border-color: var(--pvc-primary-border);--pvc-form-element-focus-color: var(--pvc-primary-border);--pvc-form-element-disabled-opacity: .5;--pvc-form-element-invalid-border-color: rgb(149.5, 74, 80);--pvc-form-element-invalid-active-border-color: rgb(183.25, 63.5, 59);--pvc-form-element-invalid-focus-color: var(--pvc-form-element-invalid-active-border-color);--pvc-form-element-valid-border-color: #2a7b6f;--pvc-form-element-valid-active-border-color: rgb(22, 137, 105.5);--pvc-form-element-valid-focus-color: var(--pvc-form-element-valid-active-border-color);--pvc-switch-background-color: #333c4e;--pvc-switch-checked-background-color: var(--pvc-primary-background);--pvc-switch-color: #fff;--pvc-switch-thumb-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-range-border-color: #202632;--pvc-range-active-border-color: #2a3140;--pvc-range-thumb-border-color: var(--pvc-background-color);--pvc-range-thumb-color: var(--pvc-secondary-background);--pvc-range-thumb-active-color: var(--pvc-primary-background);--pvc-loading-spinner-opacity: .5;--pvc-icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}[data-theme=dark] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pvc-form-element-focus-color: var(--pvc-primary-focus)}[data-theme=dark] .pvc-settings-form [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before{filter:brightness(0)}.pvc-settings-form progress,.pvc-settings-form [type=checkbox],.pvc-settings-form [type=radio],.pvc-settings-form [type=range]{accent-color:var(--pvc-primary)}.pvc-settings-form :where(a:not([role=button])),.pvc-settings-form [role=link]{--pvc-color: var(--pvc-primary);--pvc-background-color: transparent;--pvc-underline: var(--pvc-primary-underline);outline:none;background-color:var(--pvc-background-color);color:var(--pvc-color);text-decoration:var(--pvc-text-decoration);text-decoration-color:var(--pvc-underline);text-underline-offset:.125em;transition:background-color var(--pvc-transition),color var(--pvc-transition),text-decoration var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form :where(a:not([role=button])):is([aria-current]:not([aria-current=false]),:hover,:active,:focus),.pvc-settings-form [role=link]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pvc-color: var(--pvc-primary-hover);--pvc-underline: var(--pvc-primary-hover-underline);--pvc-text-decoration: underline}.pvc-settings-form :where(a:not([role=button])):focus-visible,.pvc-settings-form [role=link]:focus-visible{box-shadow:0 0 0 var(--pvc-outline-width) var(--pvc-primary-focus)}.pvc-settings-form :where(a:not([role=button])).secondary,.pvc-settings-form [role=link].secondary{--pvc-color: var(--pvc-secondary);--pvc-underline: var(--pvc-secondary-underline)}.pvc-settings-form :where(a:not([role=button])).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),.pvc-settings-form [role=link].secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pvc-color: var(--pvc-secondary-hover);--pvc-underline: var(--pvc-secondary-hover-underline)}.pvc-settings-form :where(a:not([role=button])).contrast,.pvc-settings-form [role=link].contrast{--pvc-color: var(--pvc-contrast);--pvc-underline: var(--pvc-contrast-underline)}.pvc-settings-form :where(a:not([role=button])).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),.pvc-settings-form [role=link].contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pvc-color: var(--pvc-contrast-hover);--pvc-underline: var(--pvc-contrast-hover-underline)}.pvc-settings-form a[role=button]{display:inline-block}.pvc-settings-form pre,.pvc-settings-form code,.pvc-settings-form kbd,.pvc-settings-form samp{font-size:.875em;font-family:var(--pvc-font-family)}.pvc-settings-form pre code,.pvc-settings-form pre samp{font-size:inherit;font-family:inherit}.pvc-settings-form pre{-ms-overflow-style:scrollbar;overflow:auto}.pvc-settings-form pre,.pvc-settings-form code,.pvc-settings-form kbd,.pvc-settings-form samp{border-radius:var(--pvc-border-radius);background:var(--pvc-code-background-color);color:var(--pvc-code-color);font-weight:var(--pvc-font-weight);line-height:initial}.pvc-settings-form code,.pvc-settings-form kbd,.pvc-settings-form samp{display:inline-block;padding:.375rem}.pvc-settings-form pre{display:block;margin-bottom:var(--pvc-spacing);overflow-x:auto}.pvc-settings-form pre>code,.pvc-settings-form pre>samp{display:block;padding:var(--pvc-spacing);background:none;line-height:var(--pvc-line-height)}.pvc-settings-form kbd{background-color:var(--pvc-code-kbd-background-color);color:var(--pvc-code-kbd-color);vertical-align:baseline}.pvc-settings-form hr{height:0;margin:var(--pvc-typography-spacing-vertical) 0;border:0;border-top:1px solid var(--pvc-muted-border-color);color:inherit}.pvc-settings-form [hidden],.pvc-settings-form template{display:none!important}.pvc-settings-form canvas{display:inline-block}.pvc-settings-form input,.pvc-settings-form optgroup,.pvc-settings-form select,.pvc-settings-form textarea{margin:0;font-size:1rem;line-height:var(--pvc-line-height);font-family:inherit;letter-spacing:inherit}.pvc-settings-form input{overflow:visible}.pvc-settings-form select{text-transform:none}.pvc-settings-form legend{max-width:100%;padding:0;color:inherit;white-space:normal}.pvc-settings-form textarea{overflow:auto}.pvc-settings-form [type=checkbox],.pvc-settings-form [type=radio]{padding:0}.pvc-settings-form ::-webkit-inner-spin-button,.pvc-settings-form ::-webkit-outer-spin-button{height:auto}.pvc-settings-form [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.pvc-settings-form [type=search]::-webkit-search-decoration{-webkit-appearance:none}.pvc-settings-form ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.pvc-settings-form ::-moz-focus-inner{padding:0;border-style:none}.pvc-settings-form :-moz-focusring{outline:none}.pvc-settings-form :-moz-ui-invalid{box-shadow:none}.pvc-settings-form ::-ms-expand{display:none}.pvc-settings-form [type=file],.pvc-settings-form [type=range]{padding:0;border-width:0}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings-form fieldset{width:100%;margin:0;margin-bottom:var(--pvc-spacing);padding:0;border:0}.pvc-settings-form label,.pvc-settings-form fieldset legend{display:block;margin-bottom:calc(var(--pvc-spacing) * .375);color:var(--pvc-color);font-weight:var(--pvc-form-label-font-weight, var(--pvc-font-weight))}.pvc-settings-form fieldset legend{margin-bottom:calc(var(--pvc-spacing) * .5)}.pvc-settings-form input:not([type=checkbox],[type=radio]),.pvc-settings-form button[type=submit],.pvc-settings-form select,.pvc-settings-form textarea{width:100%}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file]),.pvc-settings-form select,.pvc-settings-form textarea{appearance:none;padding:var(--pvc-form-element-spacing-vertical) var(--pvc-form-element-spacing-horizontal)}.pvc-settings-form input,.pvc-settings-form select,.pvc-settings-form textarea{--pvc-background-color: var(--pvc-form-element-background-color);--pvc-border-color: var(--pvc-form-element-border-color);--pvc-color: var(--pvc-form-element-color);--pvc-box-shadow: none;border:var(--pvc-border-width) solid var(--pvc-border-color);border-radius:var(--pvc-border-radius);outline:none;background-color:var(--pvc-background-color);box-shadow:var(--pvc-box-shadow);color:var(--pvc-color);font-weight:var(--pvc-font-weight);transition:background-color var(--pvc-transition),border-color var(--pvc-transition),color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus),.pvc-settings-form :where(select,textarea):not([readonly]):is(:active,:focus){--pvc-background-color: var(--pvc-form-element-active-background-color)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus),.pvc-settings-form :where(select,textarea):not([readonly]):is(:active,:focus){--pvc-border-color: var(--pvc-form-element-active-border-color)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus,.pvc-settings-form :where(select,textarea):not([readonly]):focus{--pvc-box-shadow: 0 0 0 var(--pvc-outline-width) var(--pvc-form-element-focus-color)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset])[disabled],.pvc-settings-form select[disabled],.pvc-settings-form textarea[disabled],.pvc-settings-form label[aria-disabled=true],.pvc-settings-form :where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea){opacity:var(--pvc-form-element-disabled-opacity);pointer-events:none}.pvc-settings-form label[aria-disabled=true] input[disabled]{opacity:1}.pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid]{padding-right:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--pvc-form-element-spacing-horizontal);padding-inline-start:var(--pvc-form-element-spacing-horizontal)!important;padding-inline-end:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}.pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=false]:not(select){background-image:var(--pvc-icon-valid)}.pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=true]:not(select){background-image:var(--pvc-icon-invalid)}.pvc-settings-form :where(input,select,textarea)[aria-invalid=false]{--pvc-border-color: var(--pvc-form-element-valid-border-color)}.pvc-settings-form :where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--pvc-border-color: var(--pvc-form-element-valid-active-border-color) !important}.pvc-settings-form :where(input,select,textarea)[aria-invalid=false]:is(:active,:focus):not([type=checkbox],[type=radio]){--pvc-box-shadow: 0 0 0 var(--pvc-outline-width) var(--pvc-form-element-valid-focus-color) !important}.pvc-settings-form :where(input,select,textarea)[aria-invalid=true]{--pvc-border-color: var(--pvc-form-element-invalid-border-color)}.pvc-settings-form :where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--pvc-border-color: var(--pvc-form-element-invalid-active-border-color) !important}.pvc-settings-form :where(input,select,textarea)[aria-invalid=true]:is(:active,:focus):not([type=checkbox],[type=radio]){--pvc-box-shadow: 0 0 0 var(--pvc-outline-width) var(--pvc-form-element-invalid-focus-color) !important}[dir=rtl] .pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}.pvc-settings-form input::placeholder,.pvc-settings-form input::-webkit-input-placeholder,.pvc-settings-form textarea::placeholder,.pvc-settings-form textarea::-webkit-input-placeholder,.pvc-settings-form select:invalid{color:var(--pvc-form-element-placeholder-color);opacity:1}.pvc-settings-form input:not([type=checkbox],[type=radio]),.pvc-settings-form select,.pvc-settings-form textarea{margin-bottom:var(--pvc-spacing)}.pvc-settings-form select::-ms-expand{border:0;background-color:transparent}.pvc-settings-form select:not([multiple],[size]){padding-right:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem);padding-left:var(--pvc-form-element-spacing-horizontal);padding-inline-start:var(--pvc-form-element-spacing-horizontal);padding-inline-end:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem);background-image:var(--pvc-icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}.pvc-settings-form select[multiple] option:checked{background:var(--pvc-form-element-selected-background-color);color:var(--pvc-form-element-color)}[dir=rtl] .pvc-settings-form select:not([multiple],[size]){background-position:center left .75rem}.pvc-settings-form textarea{display:block;resize:vertical}.pvc-settings-form textarea[aria-invalid]{--pvc-icon-height: calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2);background-position:top right .75rem!important;background-size:1rem var(--pvc-icon-height)!important}.pvc-settings-form :where(input,select,textarea,fieldset)+small{display:block;width:100%;margin-top:calc(var(--pvc-spacing) * -.75);margin-bottom:var(--pvc-spacing);color:var(--pvc-muted-color)}.pvc-settings-form :where(input,select,textarea,fieldset)[aria-invalid=false]+small{color:var(--pvc-ins-color)}.pvc-settings-form :where(input,select,textarea,fieldset)[aria-invalid=true]+small{color:var(--pvc-del-color)}.pvc-settings-form label>:where(input,select,textarea){margin-top:calc(var(--pvc-spacing) * .25)}.pvc-settings-form label:has([type=checkbox],[type=radio]){width:fit-content;cursor:pointer}.pvc-settings-form [type=checkbox],.pvc-settings-form [type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-inline-end:.5em;border-width:var(--pvc-border-width);vertical-align:middle;cursor:pointer}.pvc-settings-form [type=checkbox]::-ms-check,.pvc-settings-form [type=radio]::-ms-check{display:none}.pvc-settings-form [type=checkbox]:checked,.pvc-settings-form [type=checkbox]:checked:active,.pvc-settings-form [type=checkbox]:checked:focus,.pvc-settings-form [type=radio]:checked,.pvc-settings-form [type=radio]:checked:active,.pvc-settings-form [type=radio]:checked:focus{--pvc-background-color: var(--pvc-primary-background);--pvc-border-color: var(--pvc-primary-border);background-image:var(--pvc-icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}.pvc-settings-form [type=checkbox]~label,.pvc-settings-form [type=radio]~label{display:inline-block;margin-bottom:0;cursor:pointer}.pvc-settings-form [type=checkbox]~label:not(:last-of-type),.pvc-settings-form [type=radio]~label:not(:last-of-type){margin-inline-end:1em}.pvc-settings-form [type=checkbox]:indeterminate{--pvc-background-color: var(--pvc-primary-background);--pvc-border-color: var(--pvc-primary-border);background-image:var(--pvc-icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}.pvc-settings-form [type=radio]{border-radius:50%}.pvc-settings-form [type=radio]:checked,.pvc-settings-form [type=radio]:checked:active,.pvc-settings-form [type=radio]:checked:focus{--pvc-background-color: var(--pvc-primary-inverse);border-width:.35em;background-image:none}.pvc-settings-form [type=checkbox][role=switch]{--pvc-background-color: var(--pvc-switch-background-color);--pvc-color: var(--pvc-switch-color);width:2.25em;height:1.25em;border:var(--pvc-border-width) solid var(--pvc-border-color);border-radius:1.25em;background-color:var(--pvc-background-color);line-height:1.25em}.pvc-settings-form [type=checkbox][role=switch]:not([aria-invalid]){--pvc-border-color: var(--pvc-switch-background-color)}.pvc-settings-form [type=checkbox][role=switch]:before{display:block;aspect-ratio:1;height:100%;border-radius:50%;background-color:var(--pvc-color);box-shadow:var(--pvc-switch-thumb-box-shadow);content:"";transition:margin .1s ease-in-out}.pvc-settings-form [type=checkbox][role=switch]:focus{--pvc-background-color: var(--pvc-switch-background-color);--pvc-border-color: var(--pvc-switch-background-color)}.pvc-settings-form [type=checkbox][role=switch]:checked{--pvc-background-color: var(--pvc-switch-checked-background-color);--pvc-border-color: var(--pvc-switch-checked-background-color);background-image:none}.pvc-settings-form [type=checkbox][role=switch]:checked:before{margin-inline-start:1em}.pvc-settings-form [type=checkbox][role=switch][disabled]{--pvc-background-color: var(--pvc-border-color)}.pvc-settings-form [type=checkbox][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:focus,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:focus{--pvc-background-color: var(--pvc-form-element-valid-border-color)}.pvc-settings-form [type=checkbox]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:focus[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:focus[aria-invalid=true]{--pvc-background-color: var(--pvc-form-element-invalid-border-color)}.pvc-settings-form [type=checkbox][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:focus,.pvc-settings-form [type=radio][aria-invalid=false]:checked,.pvc-settings-form [type=radio][aria-invalid=false]:checked:active,.pvc-settings-form [type=radio][aria-invalid=false]:checked:focus,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:focus{--pvc-border-color: var(--pvc-form-element-valid-border-color)}.pvc-settings-form [type=checkbox]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:focus[aria-invalid=true],.pvc-settings-form [type=radio]:checked[aria-invalid=true],.pvc-settings-form [type=radio]:checked:active[aria-invalid=true],.pvc-settings-form [type=radio]:checked:focus[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:focus[aria-invalid=true]{--pvc-border-color: var(--pvc-form-element-invalid-border-color)}.pvc-settings-form [type=color]::-webkit-color-swatch-wrapper{padding:0}.pvc-settings-form [type=color]::-moz-focus-inner{padding:0}.pvc-settings-form [type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--pvc-border-radius) * .5)}.pvc-settings-form [type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--pvc-border-radius) * .5)}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--pvc-icon-position: .75rem;--pvc-icon-width: 1rem;padding-right:calc(var(--pvc-icon-width) + var(--pvc-icon-position));background-image:var(--pvc-icon-date);background-position:center right var(--pvc-icon-position);background-size:var(--pvc-icon-width) auto;background-repeat:no-repeat}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--pvc-icon-time)}.pvc-settings-form [type=date]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=datetime-local]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=month]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=time]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=week]::-webkit-calendar-picker-indicator{width:var(--pvc-icon-width);margin-right:calc(var(--pvc-icon-width) * -1);margin-left:var(--pvc-icon-position);opacity:0}@-moz-document url-prefix(){.pvc-settings-form [type=date],.pvc-settings-form [type=datetime-local],.pvc-settings-form [type=month],.pvc-settings-form [type=time],.pvc-settings-form [type=week]{padding-right:var(--pvc-form-element-spacing-horizontal)!important;background-image:none!important}}[dir=rtl] .pvc-settings-form :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}.pvc-settings-form [type=file]{--pvc-color: var(--pvc-muted-color);margin-left:calc(var(--pvc-outline-width) * -1);padding:calc(var(--pvc-form-element-spacing-vertical) * .5) 0;padding-left:var(--pvc-outline-width);border:0;border-radius:0;background:none}.pvc-settings-form [type=file]::file-selector-button{margin-right:calc(var(--pvc-spacing) / 2);padding:calc(var(--pvc-form-element-spacing-vertical) * .5) var(--pvc-form-element-spacing-horizontal)}.pvc-settings-form [type=file]:is(:hover,:active,:focus)::file-selector-button{--pvc-background-color: var(--pvc-secondary-hover-background);--pvc-border-color: var(--pvc-secondary-hover-border)}.pvc-settings-form [type=file]:focus::file-selector-button{--pvc-box-shadow: var(--pvc-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)), 0 0 0 var(--pvc-outline-width) var(--pvc-secondary-focus)}.pvc-settings-form [type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:none}.pvc-settings-form [type=range]::-webkit-slider-runnable-track{width:100%;height:.375rem;border-radius:var(--pvc-border-radius);background-color:var(--pvc-range-border-color);transition:background-color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form [type=range]::-moz-range-track{width:100%;height:.375rem;border-radius:var(--pvc-border-radius);background-color:var(--pvc-range-border-color);transition:background-color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form [type=range]::-ms-track{width:100%;height:.375rem;border-radius:var(--pvc-border-radius);background-color:var(--pvc-range-border-color);transition:background-color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form [type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pvc-range-thumb-border-color);border-radius:50%;background-color:var(--pvc-range-thumb-color);cursor:pointer;transition:background-color var(--pvc-transition),transform var(--pvc-transition)}.pvc-settings-form [type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pvc-range-thumb-border-color);border-radius:50%;background-color:var(--pvc-range-thumb-color);cursor:pointer;transition:background-color var(--pvc-transition),transform var(--pvc-transition)}.pvc-settings-form [type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pvc-range-thumb-border-color);border-radius:50%;background-color:var(--pvc-range-thumb-color);cursor:pointer;transition:background-color var(--pvc-transition),transform var(--pvc-transition)}.pvc-settings-form [type=range]:active,.pvc-settings-form [type=range]:focus-within{--pvc-range-border-color: var(--pvc-range-active-border-color);--pvc-range-thumb-color: var(--pvc-range-thumb-active-color)}.pvc-settings-form [type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}.pvc-settings-form [type=range]:active::-moz-range-thumb{transform:scale(1.25)}.pvc-settings-form [type=range]:active::-ms-thumb{transform:scale(1.25)}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{padding-inline-start:calc(var(--pvc-form-element-spacing-horizontal) + 1.75rem);background-image:var(--pvc-icon-search);background-position:center left calc(var(--pvc-form-element-spacing-horizontal) + .125rem);background-size:1rem auto;background-repeat:no-repeat}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{padding-inline-start:calc(var(--pvc-form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--pvc-icon-search),var(--pvc-icon-valid)}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--pvc-icon-search),var(--pvc-icon-invalid)}[dir=rtl] .pvc-settings-form :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] .pvc-settings-form :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}.pvc-settings-form [role=search],.pvc-settings-form [role=group]{display:inline-flex;position:relative;width:100%;margin-bottom:var(--pvc-spacing);border-radius:var(--pvc-border-radius);box-shadow:var(--pvc-group-box-shadow, 0 0 0 rgba(0, 0, 0, 0));vertical-align:middle;transition:box-shadow var(--pvc-transition)}.pvc-settings-form [role=search]>*,.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=search] select,.pvc-settings-form [role=group]>*,.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=group] select{position:relative;flex:1 1 auto;margin-bottom:0}.pvc-settings-form [role=search]>*:not(:first-child),.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=search] select:not(:first-child),.pvc-settings-form [role=group]>*:not(:first-child),.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=group] select:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.pvc-settings-form [role=search]>*:not(:last-child),.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):not(:last-child),.pvc-settings-form [role=search] select:not(:last-child),.pvc-settings-form [role=group]>*:not(:last-child),.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):not(:last-child),.pvc-settings-form [role=group] select:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.pvc-settings-form [role=search]>*:focus,.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):focus,.pvc-settings-form [role=search] select:focus,.pvc-settings-form [role=group]>*:focus,.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):focus,.pvc-settings-form [role=group] select:focus{z-index:2}.pvc-settings-form [role=search] button:not(:first-child),.pvc-settings-form [role=search] [type=submit]:not(:first-child),.pvc-settings-form [role=search] [type=reset]:not(:first-child),.pvc-settings-form [role=search] [type=button]:not(:first-child),.pvc-settings-form [role=search] [role=button]:not(:first-child),.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=search] select:not(:first-child),.pvc-settings-form [role=group] button:not(:first-child),.pvc-settings-form [role=group] [type=submit]:not(:first-child),.pvc-settings-form [role=group] [type=reset]:not(:first-child),.pvc-settings-form [role=group] [type=button]:not(:first-child),.pvc-settings-form [role=group] [role=button]:not(:first-child),.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=group] select:not(:first-child){margin-left:calc(var(--pvc-border-width) * -1)}.pvc-settings-form [role=search] button,.pvc-settings-form [role=search] [type=submit],.pvc-settings-form [role=search] [type=reset],.pvc-settings-form [role=search] [type=button],.pvc-settings-form [role=search] [role=button],.pvc-settings-form [role=group] button,.pvc-settings-form [role=group] [type=submit],.pvc-settings-form [role=group] [type=reset],.pvc-settings-form [role=group] [type=button],.pvc-settings-form [role=group] [role=button]{width:auto}@supports selector(:has(*)){.pvc-settings-form [role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus),.pvc-settings-form [role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus){--pvc-group-box-shadow: var(--pvc-group-box-shadow-focus-with-button)}.pvc-settings-form [role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select,.pvc-settings-form [role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select{border-color:transparent}.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus),.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus){--pvc-group-box-shadow: var(--pvc-group-box-shadow-focus-with-input)}.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) button,.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) button,.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button]{--pvc-button-box-shadow: 0 0 0 var(--pvc-border-width) var(--pvc-primary-border);--pvc-button-hover-box-shadow: 0 0 0 var(--pvc-border-width) var(--pvc-primary-hover-border)}.pvc-settings-form [role=search] button:focus,.pvc-settings-form [role=search] [type=submit]:focus,.pvc-settings-form [role=search] [type=reset]:focus,.pvc-settings-form [role=search] [type=button]:focus,.pvc-settings-form [role=search] [role=button]:focus,.pvc-settings-form [role=group] button:focus,.pvc-settings-form [role=group] [type=submit]:focus,.pvc-settings-form [role=group] [type=reset]:focus,.pvc-settings-form [role=group] [type=button]:focus,.pvc-settings-form [role=group] [role=button]:focus{box-shadow:none}}.pvc-settings-form [role=search]>*:first-child{border-top-left-radius:5rem;border-bottom-left-radius:5rem}.pvc-settings-form [role=search]>*:last-child{border-top-right-radius:5rem;border-bottom-right-radius:5rem}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form){white-space:nowrap}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form):before{display:inline-block;width:1em;height:1em;background-image:var(--pvc-icon-loading);background-size:1em auto;background-repeat:no-repeat;content:"";vertical-align:-.125em}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form):not(:empty):before{margin-inline-end:calc(var(--pvc-spacing) * .5)}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form):empty{text-align:center}.pvc-settings-form button[aria-busy=true],.pvc-settings-form [type=submit][aria-busy=true],.pvc-settings-form [type=button][aria-busy=true],.pvc-settings-form [type=reset][aria-busy=true],.pvc-settings-form [role=button][aria-busy=true],.pvc-settings-form a[aria-busy=true]{pointer-events:none}.pvc-settings-form [aria-controls]{cursor:pointer}.pvc-settings-form [aria-disabled=true],.pvc-settings-form [disabled]{cursor:not-allowed}.pvc-settings-form [aria-hidden=false][hidden]{display:initial}.pvc-settings-form [aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}.pvc-settings-form a,.pvc-settings-form area,.pvc-settings-form button,.pvc-settings-form input,.pvc-settings-form label,.pvc-settings-form select,.pvc-settings-form summary,.pvc-settings-form textarea,.pvc-settings-form [tabindex]{-ms-touch-action:manipulation}.pvc-settings-form [dir=rtl]{direction:rtl}.pvc-settings-wrapper{--pvc-theme-color: var(--wp-admin-theme-color, #2271b1);--pvc-theme-color-rgb: var(--wp-admin-theme-color--rgb, 34, 113, 177);--pvc-theme-color-darker-10: var(--wp-admin-theme-color-darker-10, #135e96);--pvc-border-width-focus: var(--wp-admin-border-width-focus, 2px);--pvc-surface: #fff;--pvc-surface-muted: #ebebeb;--pvc-text: #3c434a;--pvc-text-strong: #070707;--pvc-text-input: #2c3338;--pvc-text-muted: #757575;--pvc-border: #c3c4c7;--pvc-border-input: #8c8f94;--pvc-button-bg: #f6f7f7;--pvc-button-bg-hover: #f0f0f1;--pvc-button-border: #8c8f94;--pvc-button-border-hover: #757575;--pvc-button-text: #2c3338;--pvc-button-text-hover: #070707;--pvc-button-focus: var(--pvc-theme-color);--pvc-font-family-emoji: inherit;--pvc-font-family-sans-serif: inherit;--pvc-font-family-monospace: inherit;--pvc-font-family: var(--pvc-font-family-sans-serif);--pvc-line-height: 1.5;--pvc-font-weight: 400;--pvc-font-size: 100%;--pvc-text-underline-offset: .1rem;--pvc-border-radius: .25rem;--pvc-border-width: .0625rem;--pvc-outline-width: .125rem;--pvc-transition: .2s ease-in-out;--pvc-spacing: 1rem;--pvc-typography-spacing-vertical: 1rem;--pvc-block-spacing-vertical: 20px;--pvc-block-spacing-horizontal: 20px;--pvc-grid-column-gap: 20px;--pvc-grid-row-gap: 20px;--pvc-form-element-spacing-vertical: .45rem;--pvc-form-element-spacing-horizontal: .8rem;--pvc-form-element-disabled-opacity: .6;--pvc-group-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-primary-focus);--pvc-group-box-shadow-focus-with-input: 0 0 0 .0625rem var(--pvc-form-element-border-color);--pvc-modal-overlay-backdrop-filter: blur(.375rem);--pvc-nav-element-spacing-vertical: 1rem;--pvc-nav-element-spacing-horizontal: .5rem;--pvc-nav-link-spacing-vertical: .5rem;--pvc-nav-link-spacing-horizontal: .5rem;--pvc-nav-breadcrumb-divider: ">";--pvc-primary: var(--pvc-theme-color);--pvc-primary-background: var(--pvc-theme-color);--pvc-primary-border: var(--pvc-theme-color);--pvc-primary-underline: rgba(var(--pvc-theme-color-rgb), .5);--pvc-primary-hover: var(--pvc-theme-color-darker-10);--pvc-primary-hover-background: var(--pvc-theme-color-darker-10);--pvc-primary-hover-border: var(--pvc-theme-color-darker-10);--pvc-primary-hover-underline: var(--pvc-theme-color-darker-10);--pvc-primary-focus: rgba(var(--pvc-theme-color-rgb), .25);--pvc-primary-inverse: #fff;--pvc-secondary: var(--pvc-button-text);--pvc-secondary-background: var(--pvc-button-bg);--pvc-secondary-border: var(--pvc-button-border);--pvc-secondary-underline: rgba(var(--pvc-theme-color-rgb), .4);--pvc-secondary-hover: var(--pvc-button-text-hover);--pvc-secondary-hover-background: var(--pvc-button-bg-hover);--pvc-secondary-hover-border: var(--pvc-button-border-hover);--pvc-secondary-hover-underline: var(--pvc-button-border-hover);--pvc-secondary-focus: var(--pvc-button-focus);--pvc-secondary-inverse: var(--pvc-button-text);--pvc-contrast: var(--pvc-text-strong);--pvc-contrast-background: var(--pvc-text-strong);--pvc-contrast-border: var(--pvc-text-strong);--pvc-contrast-hover: #000;--pvc-contrast-hover-background: #000;--pvc-contrast-hover-border: #000;--pvc-contrast-focus: rgba(var(--pvc-theme-color-rgb), .25);--pvc-contrast-inverse: #fff;color-scheme:light;--pvc-background-color: var(--pvc-surface);--pvc-color: var(--pvc-text);--pvc-muted-color: var(--pvc-text-muted);--pvc-muted-border-color: var(--pvc-border);--pvc-box-shadow: 0 1px 1px rgba(0, 0, 0, .04);--pvc-text-selection-color: rgba(var(--pvc-theme-color-rgb), .25);--pvc-table-border-color: var(--pvc-border);--pvc-table-row-stripped-background-color: var(--pvc-surface-muted);--pvc-form-element-background-color: var(--pvc-surface);--pvc-form-element-active-background-color: var(--pvc-surface);--pvc-form-element-selected-background-color: var(--pvc-surface-muted);--pvc-form-element-border-color: var(--pvc-border-input);--pvc-form-element-color: var(--pvc-text-input);--pvc-form-element-placeholder-color: var(--pvc-text-muted);--pvc-form-element-active-border-color: var(--pvc-theme-color);--pvc-form-element-focus-color: var(--pvc-theme-color);--pvc-switch-background-color: var(--pvc-border-input);--pvc-switch-checked-background-color: var(--pvc-theme-color);--pvc-switch-color: #fff;--pvc-outline-width: var(--pvc-border-width-focus);--pvc-block-spacing: var(--pvc-block-spacing-vertical) var(--pvc-block-spacing-horizontal);--pvc-form-element-spacing: var(--pvc-form-element-spacing-vertical) var(--pvc-form-element-spacing-horizontal);--pvc-typography-spacing: var(--pvc-typography-spacing-vertical)}.pvc-settings-wrapper .button.button-secondary{--pvc-primary: var(--pvc-secondary);--pvc-primary-background: var(--pvc-secondary-background);--pvc-primary-border: var(--pvc-secondary-border);--pvc-primary-hover: var(--pvc-secondary-hover);--pvc-primary-hover-background: var(--pvc-secondary-hover-background);--pvc-primary-hover-border: var(--pvc-secondary-hover-border);--pvc-primary-hover-underline: var(--pvc-secondary-hover-underline);--pvc-primary-focus: var(--pvc-secondary-focus);--pvc-primary-inverse: var(--pvc-secondary-inverse)}.pvc-settings-wrapper code,.pvc-settings-wrapper kbd,.pvc-settings-wrapper samp{background:#f0f0f1;background:#00000012;color:var(--pvc-text)}.wp-admin #wpcontent{padding:0}.wp-admin #wpbody-content>.notice,.wp-admin #wpbody-content>.error,.wp-admin #wpbody-content>.updated,.wp-admin #wpbody-content>.info{display:none}.wp-admin .wrap{margin:0}.pvc-settings-wrapper .header-wrapper{padding:20px 40px;background-color:var(--pvc-surface);border-bottom:1px solid var(--pvc-surface-muted)}.pvc-settings-wrapper .content-wrapper{padding:0 40px}.pvc-settings-wrapper .header-title{font-weight:600;font-size:18px;line-height:1;color:var(--pvc-text-strong)}.pvc-settings-wrapper .nav-tab-wrapper{display:flex;flex-wrap:wrap;list-style:none;padding:10px 40px 0;gap:30px;margin:0 0 20px;background:var(--pvc-surface);border-bottom:1px solid var(--pvc-surface-muted)}.pvc-settings-wrapper .nav-tab-wrapper .nav-tab{margin:2px 0 0;border:0;background:none;font-weight:600;font-size:14px;line-height:20px;padding:0 0 10px;text-decoration:none;border-bottom:2px solid transparent}.pvc-settings-wrapper .nav-tab-wrapper .nav-tab:hover,.pvc-settings-wrapper .nav-tab-wrapper .nav-tab:focus{color:var(--wp-admin-theme-color);outline:none;box-shadow:none}.pvc-settings-wrapper .nav-tab-wrapper .nav-tab.nav-tab-active{border-bottom-color:var(--wp-admin-theme-color)}.pvc-settings form{min-width:463px;width:auto;flex:1 1 auto}.pvc-settings form input[type=radio]:checked{background-color:var(--pvc-form-element-background-color)}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]){width:auto;min-width:80px;max-width:100%;font-size:var(--pvc-font-size);line-height:var(--pvc-line-height);border-radius:var(--pvc-border-radius);margin-bottom:0;padding:var(--pvc-form-element-spacing-vertical) var(--pvc-form-element-spacing-horizontal);min-height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]).large-text{width:100%}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]).regular-text{width:25rem}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]).small-text{width:8rem}.pvc-settings [type=search]{--pvc-border-radius: .25rem}.pvc-settings select,.pvc-settings textarea{width:auto;max-width:100%;font-size:var(--pvc-font-size);line-height:var(--pvc-line-height);margin-bottom:0}.pvc-settings select{width:25rem;min-height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings [type=submit].button,.pvc-settings [type=button].button{width:auto;font-size:var(--pvc-font-size);line-height:var(--pvc-line-height);border-radius:var(--pvc-border-radius);min-height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings [type=submit].button.button-small,.pvc-settings [type=button].button.button-small{font-size:calc(var(--pvc-font-size) * .875);height:auto}.pvc-settings span[role=button]{background:none;border:none;padding:0;margin:0;font-size:inherit}.pvc-settings .submit{display:flex;gap:10px}.pvc-settings .pvc-sidebar{width:300px;flex:0 0 300px;margin-left:20px}.pvc-settings.has-sidebar{display:flex;justify-content:space-between}@media(max-width:960px){.pvc-settings.has-sidebar{flex-direction:column}.pvc-settings form{width:100%}.pvc-settings .pvc-sidebar{width:100%;flex:0 0 auto;margin-left:0;margin-top:20px}}.pvc-settings p.help,.pvc-settings p.description,.pvc-settings span.description{font-size:13px;font-style:italic;color:var(--pvc-text-muted)}.pvc-range-field{display:flex;gap:10px;align-items:center}.pvc-range-field input[type=range]{appearance:none;color-scheme:light;background:transparent;accent-color:var(--pvc-theme-color)}.pvc-range-field input[type=range]::-webkit-slider-runnable-track{height:4px;background:#dcdcde;border-radius:999px}.pvc-range-field input[type=range]::-webkit-slider-thumb{appearance:none;width:16px;height:16px;margin-top:-6px;border-radius:50%;background:var(--pvc-theme-color);border:1px solid var(--pvc-theme-color)}.pvc-range-field input[type=range]::-moz-range-track{height:4px;background:#dcdcde;border-radius:999px}.pvc-range-field input[type=range]::-moz-range-progress{height:4px;background:var(--pvc-theme-color);border-radius:999px}.pvc-range-field input[type=range]::-moz-range-thumb{width:16px;height:16px;border-radius:50%;background:var(--pvc-theme-color);border:1px solid var(--pvc-theme-color)}.pvc-buttons-group{display:flex;gap:10px}.pvc-buttons-group [type=submit].button,.pvc-buttons-group [type=button].button{margin:0}.pvc-field-group label{margin-right:10px}.pvc-field-group.horizontal label{display:inline-block}.pvc-field-group.vertical label{display:block;margin-bottom:8px}.pvc-field input[type=checkbox]:checked:not([role=switch]):before,.pvc-field input[type=radio]:checked:before{display:none}.pvc-field input[type=checkbox][role=switch]:checked:before{width:auto;margin-top:0;margin-bottom:0}.pvc-disabled{opacity:var(--pvc-form-element-disabled-opacity);cursor:not-allowed}.pvc-disabled [type=radio]{border-color:var(--pvc-form-element-border-color)}.pvc-disabled select[disabled]{opacity:1}.pvc-field-type-color .pvc-color-control{display:flex;gap:10px;align-items:center;position:relative;width:fit-content}.pvc-field-type-color .pvc-color-control button{margin-bottom:0}.pvc-field-type-color .pvc-color-input{min-width:8rem}.pvc-field-type-color .pvc-color-swatch{width:32px;height:32px;padding:0;border-radius:var(--pvc-border-radius);border:1px solid var(--pvc-form-element-border-color);box-shadow:inset 0 0 0 2px var(--pvc-form-element-background-color);cursor:pointer;flex-shrink:0}.pvc-field-type-color .pvc-color-swatch:focus{outline:none;box-shadow:inset 0 0 0 2px var(--pvc-form-element-background-color),0 0 0 2px var(--pvc-form-element-focus-color)}.pvc-field-type-color .pvc-color-popover{position:absolute;top:calc(100% + 6px);left:0;padding:8px;border-radius:var(--pvc-border-radius);border:1px solid var(--pvc-form-element-border-color);background:var(--pvc-form-element-background-color);box-shadow:0 6px 18px #0000001f;z-index:1000;display:none;pointer-events:auto}.pvc-field-type-color.is-open .pvc-color-popover{display:block}.pvc-field-type-color hex-color-picker{width:200px;height:200px;pointer-events:auto}.pvc- hidden{display:none!important}@keyframes pvc-fade-in{0%{opacity:0}to{opacity:1}}@keyframes pvc-fade-out{0%{opacity:1}to{opacity:0}}@keyframes pvc-slide-in{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes pvc-slide-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-10px)}}.pvc-anim-in,.pvc-anim-out{animation-duration:var(--pvc-animation-duration, .25s);animation-fill-mode:both}.pvc-anim-fade.pvc-anim-in{animation-name:pvc-fade-in}.pvc-anim-fade.pvc-anim-out{animation-name:pvc-fade-out}.pvc-anim-slide.pvc-anim-in{animation-name:pvc-slide-in}.pvc-anim-slide.pvc-anim-out{animation-name:pvc-slide-out}.post-views-counter-settings.has-sidebar{display:flex;flex-direction:row;gap:30px;justify-content:space-between}.post-views-counter-settings form{min-width:463px;width:auto;position:relative}.post-views-counter-settings p.help,.post-views-counter-settings p.description{font-size:13px;font-style:italic;line-height:1.6}.post-views-counter-settings .pvc-template-tags-list{display:block;margin-top:5px;font-style:normal}.post-views-counter-settings select{vertical-align:top;width:auto}.post-views-counter-settings .available{color:#00a32a}.post-views-counter-settings .unavailable{color:#d63638}.post-views-counter-settings .pvc-ip-box-group{margin-bottom:10px}.post-views-counter-settings .pvc-ip-box{margin-bottom:5px}.post-views-counter-settings .pvc-button{color:#fff;background-color:#6610f2;border-color:#6610f2;border-radius:.25rem}.post-views-counter-settings .pvc-button:active,.post-views-counter-settings .pvc-button:focus,.post-views-counter-settings .pvc-button:hover{color:#fff;background-color:#570ece;border-color:#570ece}.post-views-counter-settings .pvc-button:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #6610f2}.post-views-counter-settings tr.pvc-pro th:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600}.post-views-counter-settings label.pvc-pro:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600;font-style:normal}.post-views-sidebar{margin:15px 0;position:relative;order:1}.post-views-sidebar>div:not(:last-child){margin-bottom:3em}.post-views-sidebar .inner{padding:1.5em}.post-views-sidebar .inner img{max-width:80%;height:auto;display:block;margin:20px auto}.pvc-status-table .pvc-status{display:inline-block}.pvc-status-table .pvc-status-active{color:#00a32a}.pvc-status-table .pvc-status-missing{color:#d63638}.pvc-subfield{margin-top:12px}.is-hidden{display:none!important;visibility:hidden!important}output{display:block;font-size:30px;font-weight:700;text-align:center;margin:30px 0;width:100%}.post-views-credits{background:#fff;box-shadow:0 0 0 1px #0000000d}.post-views-credits .inner{text-align:center;margin:0}.post-views-credits p:first-child{margin-top:0}.post-views-credits .pvc-sidebar-title{font-size:17px;font-weight:700;margin:.5rem 0 1rem}.post-views-credits .pvc-sidebar-title:after{content:"PRO";display:inline-block;margin-left:6px;padding:0 4px 1px;font-size:14px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600}.post-views-credits .pvc-sidebar-subtitle{font-size:15px;font-weight:600;color:#1d2327;text-align:center;margin:1rem 0 1.5rem}.post-views-credits .pvc-sidebar-one-liner{text-align:center;margin-top:1.5rem}.post-views-credits .pvc-sidebar-body{font-size:14px;text-align:left;margin:1.5rem 0 2rem;padding:0}.post-views-credits .pvc-sidebar-body p{font-size:inherit;padding-left:20px;margin:.75rem 0;position:relative}.post-views-credits .pvc-sidebar-body b{color:#000}.post-views-credits .pvc-sidebar-body .pvc-icon{position:absolute;top:1px;left:0}.post-views-credits .pvc-sidebar-body .pvc-icon-check{box-sizing:border-box;display:block;transform:scale(1);width:16px;height:22px;border-radius:100px}.post-views-credits .pvc-sidebar-body .pvc-icon-check:after{content:"";display:block;box-sizing:border-box;position:absolute;left:0;top:0;width:6px;height:10px;border-width:0 2px 2px 0;border-style:solid;transform-origin:bottom left;transform:rotate(45deg)}#post_views_counter_other_license_setting .pvc-status-icon{vertical-align:middle;margin-left:8px;padding-bottom:3px}#post_views_counter_other_license_setting .pvc-status-icon:before{content:"\2717";color:#d63638}#post_views_counter_other_license_setting.license-status .pvc-status-icon:before{content:"\2717";color:#d63638}#post_views_counter_other_license_setting.license-status.valid .pvc-status-icon:before{content:"\2713";color:#00a32a}#pvc-reports-upgrade{position:absolute;left:0;top:0;height:100%;width:100%;overflow:hidden;box-sizing:border-box;min-height:400px}#pvc-reports-upgrade #pvc-reports-modal{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);padding:1.5em 3em;box-shadow:0 0 25px 10px #0000001a;border-radius:3px;background-color:#fff;text-align:center;width:26em}#pvc-reports-upgrade #pvc-reports-modal p{margin:0}#pvc-reports-upgrade #pvc-reports-modal h2{font-size:21px;font-weight:400;margin:0 0 10px;padding:9px 0 4px;line-height:1.3}#pvc-reports-upgrade #pvc-reports-modal .button{margin-top:25px;margin-bottom:10px}#pvc-reports-bg{width:100%;height:auto;opacity:.8;filter:blur(2px)}@media only screen and (max-width:960px){.post-views-counter-settings{flex-wrap:wrap}.post-views-counter-settings .post-views-sidebar{width:100%}}.pvc-provider-radio{display:inline-block;margin-right:20px;font-weight:400}.pvc-provider-radio input[type=radio]{margin-right:5px}.pvc-provider-content{margin:0}.pvc-provider-fields{padding:0;margin-top:15px}.pvc-provider-fields label{font-weight:600;margin-bottom:5px;display:block}.pvc-provider-fields input.regular-text{margin-top:5px}.pvc-provider-unavailable{color:#d63638;font-style:italic}.pvc-import-strategy{margin-bottom:25px}.pvc-field>label{margin-bottom:0}.pvc-field-group label{margin-right:8px}.pvc-radio-vertical label{display:block;margin:6px 0;font-weight:400}.pvc-radio-vertical input[type=radio]{margin-right:5px}.pvc-import-actions{padding-top:10px}.pvc-import-actions .button{margin-right:10px}.pvc-import-actions .button-primary{font-weight:600}.pvc-integration-content.unavailable{color:inherit;pointer-events:none}.pvc-integration-content.unavailable .pvc-integration-items{display:none}.pvc-integration-content input[type=checkbox]{margin-right:10px}.pvc-integration-content label{display:block;cursor:pointer}.pvc-integration-content .pvc-integration-items{margin:15px 0 0;padding-left:13px;font-size:13px;font-style:italic}.pvc-integration-content .pvc-integration-items li{margin-bottom:5px;list-style:disc}.pvc-integration-content .pvc-integration-items li:last-child{margin-bottom:0}.mce-container[role=group]{margin:0;display:block}4 */:root,:host{--pvc-font-family-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--pvc-font-family-sans-serif: system-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, Helvetica, Arial, "Helvetica Neue", sans-serif, var(--pvc-font-family-emoji);--pvc-font-family-monospace: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace, var(--pvc-font-family-emoji);--pvc-font-family: var(--pvc-font-family-sans-serif);--pvc-line-height: 1.5;--pvc-font-weight: 400;--pvc-font-size: 100%;--pvc-text-underline-offset: .1rem;--pvc-border-radius: .25rem;--pvc-border-width: .0625rem;--pvc-outline-width: .125rem;--pvc-transition: .2s ease-in-out;--pvc-spacing: 1rem;--pvc-group-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-primary-focus);--pvc-group-box-shadow-focus-with-input: 0 0 0 .0625rem var(--pvc-form-element-border-color);--pvc-icon-checkbox: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--pvc-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-date: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--pvc-icon-time: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--pvc-icon-loading: url("data:image/svg+xml,%3Csvg fill='none' height='24' width='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cstyle%3E g %7B animation: rotate 2s linear infinite; transform-origin: center center; %7D circle %7B stroke-dasharray: 75,100; stroke-dashoffset: -5; animation: dash 1.5s ease-in-out infinite; stroke-linecap: round; %7D @keyframes rotate %7B 0%25 %7B transform: rotate(0deg); %7D 100%25 %7B transform: rotate(360deg); %7D %7D @keyframes dash %7B 0%25 %7B stroke-dasharray: 1,100; stroke-dashoffset: 0; %7D 50%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -17.5; %7D 100%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -62; %7D %7D %3C/style%3E%3Cg%3E%3Ccircle cx='12' cy='12' r='10' fill='none' stroke='rgb(136, 145, 164)' stroke-width='4' /%3E%3C/g%3E%3C/svg%3E")}@media(min-width:576px){:root,:host{--pvc-font-size: 106.25%}}@media(min-width:768px){:root,:host{--pvc-font-size: 112.5%}}@media(min-width:1024px){:root,:host{--pvc-font-size: 118.75%}}@media(min-width:1280px){:root,:host{--pvc-font-size: 125%}}@media(min-width:1536px){:root,:host{--pvc-font-size: 131.25%}}a,a.secondary,a.contrast{--pvc-text-decoration: underline}pre,code,kbd,samp{--pvc-font-family: var(--pvc-font-family-monospace)}kbd{--pvc-font-weight: bolder}input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:where(select,textarea){--pvc-outline-width: .0625rem}[type=search]{--pvc-border-radius: 5rem}[type=checkbox],[type=radio]{--pvc-border-width: .125rem}[type=checkbox][role=switch]{--pvc-border-width: .1875rem}[role=search]{--pvc-border-radius: 5rem}[role=search]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus),[role=group]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus){--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-secondary-focus)}[role=search]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus),[role=group]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus){--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-contrast-focus)}[role=search] button,[role=search] [type=submit],[role=search] [type=button],[role=search] [role=button],[role=group] button,[role=group] [type=submit],[role=group] [type=button],[role=group] [role=button]{--pvc-form-element-spacing-horizontal: 2rem}.pvc-settings-form [aria-busy=true]:not(input,select,textarea):is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before{filter:brightness(0) invert(1)}[data-theme=light],:root:not([data-theme=dark]),:host(:not([data-theme=dark])){color-scheme:light;--pvc-background-color: #fff;--pvc-color: #373c44;--pvc-text-selection-color: rgba(2, 154, 232, .25);--pvc-muted-color: #646b79;--pvc-muted-border-color: rgb(231, 234, 239.5);--pvc-primary: #0172ad;--pvc-primary-background: #0172ad;--pvc-primary-border: var(--pvc-primary-background);--pvc-primary-underline: rgba(1, 114, 173, .5);--pvc-primary-hover: #015887;--pvc-primary-hover-background: #02659a;--pvc-primary-hover-border: var(--pvc-primary-hover-background);--pvc-primary-hover-underline: var(--pvc-primary-hover);--pvc-primary-focus: rgba(2, 154, 232, .5);--pvc-primary-inverse: #fff;--pvc-secondary: #5d6b89;--pvc-secondary-background: #525f7a;--pvc-secondary-border: var(--pvc-secondary-background);--pvc-secondary-underline: rgba(93, 107, 137, .5);--pvc-secondary-hover: #48536b;--pvc-secondary-hover-background: #48536b;--pvc-secondary-hover-border: var(--pvc-secondary-hover-background);--pvc-secondary-hover-underline: var(--pvc-secondary-hover);--pvc-secondary-focus: rgba(93, 107, 137, .25);--pvc-secondary-inverse: #fff;--pvc-contrast: #181c25;--pvc-contrast-background: #181c25;--pvc-contrast-border: var(--pvc-contrast-background);--pvc-contrast-underline: rgba(24, 28, 37, .5);--pvc-contrast-hover: #000;--pvc-contrast-hover-background: #000;--pvc-contrast-hover-border: var(--pvc-contrast-hover-background);--pvc-contrast-hover-underline: var(--pvc-secondary-hover);--pvc-contrast-focus: rgba(93, 107, 137, .25);--pvc-contrast-inverse: #fff;--pvc-box-shadow: .0145rem .029rem .174rem rgba(129, 145, 181, .01698), .0335rem .067rem .402rem rgba(129, 145, 181, .024), .0625rem .125rem .75rem rgba(129, 145, 181, .03), .1125rem .225rem 1.35rem rgba(129, 145, 181, .036), .2085rem .417rem 2.502rem rgba(129, 145, 181, .04302), .5rem 1rem 6rem rgba(129, 145, 181, .06), 0 0 0 .0625rem rgba(129, 145, 181, .015);--pvc-code-background-color: rgb(243, 244.5, 246.75);--pvc-code-color: #646b79;--pvc-code-kbd-background-color: var(--pvc-color);--pvc-code-kbd-color: var(--pvc-background-color);--pvc-form-element-background-color: rgb(251, 251.5, 252.25);--pvc-form-element-selected-background-color: #dfe3eb;--pvc-form-element-border-color: #cfd5e2;--pvc-form-element-color: #23262c;--pvc-form-element-placeholder-color: var(--pvc-muted-color);--pvc-form-element-active-background-color: #fff;--pvc-form-element-active-border-color: var(--pvc-primary-border);--pvc-form-element-focus-color: var(--pvc-primary-border);--pvc-form-element-disabled-opacity: .5;--pvc-form-element-invalid-border-color: rgb(183.5, 105.5, 106.5);--pvc-form-element-invalid-active-border-color: rgb(200.25, 79.25, 72.25);--pvc-form-element-invalid-focus-color: var(--pvc-form-element-invalid-active-border-color);--pvc-form-element-valid-border-color: rgb(76, 154.5, 137.5);--pvc-form-element-valid-active-border-color: rgb(39, 152.75, 118.75);--pvc-form-element-valid-focus-color: var(--pvc-form-element-valid-active-border-color);--pvc-switch-background-color: #bfc7d9;--pvc-switch-checked-background-color: var(--pvc-primary-background);--pvc-switch-color: #fff;--pvc-switch-thumb-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-range-border-color: #dfe3eb;--pvc-range-active-border-color: #bfc7d9;--pvc-range-thumb-border-color: var(--pvc-background-color);--pvc-range-thumb-color: var(--pvc-secondary-background);--pvc-range-thumb-active-color: var(--pvc-primary-background);--pvc-loading-spinner-opacity: .5;--pvc-icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(76, 154.5, 137.5)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(200.25, 79.25, 72.25)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}[data-theme=light] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:root:not([data-theme=dark]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:host(:not([data-theme=dark])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pvc-form-element-focus-color: var(--pvc-primary-focus)}@media only screen and (prefers-color-scheme:dark){:root:not([data-theme]),:host(:not([data-theme])){color-scheme:dark;--pvc-background-color: rgb(19, 22.5, 30.5);--pvc-color: #c2c7d0;--pvc-text-selection-color: rgba(1, 170, 255, .1875);--pvc-muted-color: #7b8495;--pvc-muted-border-color: #202632;--pvc-primary: #01aaff;--pvc-primary-background: #0172ad;--pvc-primary-border: var(--pvc-primary-background);--pvc-primary-underline: rgba(1, 170, 255, .5);--pvc-primary-hover: #79c0ff;--pvc-primary-hover-background: #017fc0;--pvc-primary-hover-border: var(--pvc-primary-hover-background);--pvc-primary-hover-underline: var(--pvc-primary-hover);--pvc-primary-focus: rgba(1, 170, 255, .375);--pvc-primary-inverse: #fff;--pvc-secondary: #969eaf;--pvc-secondary-background: #525f7a;--pvc-secondary-border: var(--pvc-secondary-background);--pvc-secondary-underline: rgba(150, 158, 175, .5);--pvc-secondary-hover: #b3b9c5;--pvc-secondary-hover-background: #5d6b89;--pvc-secondary-hover-border: var(--pvc-secondary-hover-background);--pvc-secondary-hover-underline: var(--pvc-secondary-hover);--pvc-secondary-focus: rgba(144, 158, 190, .25);--pvc-secondary-inverse: #fff;--pvc-contrast: #dfe3eb;--pvc-contrast-background: #eff1f4;--pvc-contrast-border: var(--pvc-contrast-background);--pvc-contrast-underline: rgba(223, 227, 235, .5);--pvc-contrast-hover: #fff;--pvc-contrast-hover-background: #fff;--pvc-contrast-hover-border: var(--pvc-contrast-hover-background);--pvc-contrast-hover-underline: var(--pvc-contrast-hover);--pvc-contrast-focus: rgba(207, 213, 226, .25);--pvc-contrast-inverse: #000;--pvc-box-shadow: .0145rem .029rem .174rem rgba(7, 8.5, 12, .01698), .0335rem .067rem .402rem rgba(7, 8.5, 12, .024), .0625rem .125rem .75rem rgba(7, 8.5, 12, .03), .1125rem .225rem 1.35rem rgba(7, 8.5, 12, .036), .2085rem .417rem 2.502rem rgba(7, 8.5, 12, .04302), .5rem 1rem 6rem rgba(7, 8.5, 12, .06), 0 0 0 .0625rem rgba(7, 8.5, 12, .015);--pvc-code-background-color: rgb(26, 30.5, 40.25);--pvc-code-color: #8891a4;--pvc-code-kbd-background-color: var(--pvc-color);--pvc-code-kbd-color: var(--pvc-background-color);--pvc-form-element-background-color: rgb(28, 33, 43.5);--pvc-form-element-selected-background-color: #2a3140;--pvc-form-element-border-color: #2a3140;--pvc-form-element-color: #e0e3e7;--pvc-form-element-placeholder-color: #8891a4;--pvc-form-element-active-background-color: rgb(26, 30.5, 40.25);--pvc-form-element-active-border-color: var(--pvc-primary-border);--pvc-form-element-focus-color: var(--pvc-primary-border);--pvc-form-element-disabled-opacity: .5;--pvc-form-element-invalid-border-color: rgb(149.5, 74, 80);--pvc-form-element-invalid-active-border-color: rgb(183.25, 63.5, 59);--pvc-form-element-invalid-focus-color: var(--pvc-form-element-invalid-active-border-color);--pvc-form-element-valid-border-color: #2a7b6f;--pvc-form-element-valid-active-border-color: rgb(22, 137, 105.5);--pvc-form-element-valid-focus-color: var(--pvc-form-element-valid-active-border-color);--pvc-switch-background-color: #333c4e;--pvc-switch-checked-background-color: var(--pvc-primary-background);--pvc-switch-color: #fff;--pvc-switch-thumb-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-range-border-color: #202632;--pvc-range-active-border-color: #2a3140;--pvc-range-thumb-border-color: var(--pvc-background-color);--pvc-range-thumb-color: var(--pvc-secondary-background);--pvc-range-thumb-active-color: var(--pvc-primary-background);--pvc-loading-spinner-opacity: .5;--pvc-icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}:root:not([data-theme]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:host(:not([data-theme])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pvc-form-element-focus-color: var(--pvc-primary-focus)}:root:not([data-theme]) .pvc-settings-form [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before,:host(:not([data-theme])) .pvc-settings-form [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before{filter:brightness(0)}}[data-theme=dark]{color-scheme:dark;--pvc-background-color: rgb(19, 22.5, 30.5);--pvc-color: #c2c7d0;--pvc-text-selection-color: rgba(1, 170, 255, .1875);--pvc-muted-color: #7b8495;--pvc-muted-border-color: #202632;--pvc-primary: #01aaff;--pvc-primary-background: #0172ad;--pvc-primary-border: var(--pvc-primary-background);--pvc-primary-underline: rgba(1, 170, 255, .5);--pvc-primary-hover: #79c0ff;--pvc-primary-hover-background: #017fc0;--pvc-primary-hover-border: var(--pvc-primary-hover-background);--pvc-primary-hover-underline: var(--pvc-primary-hover);--pvc-primary-focus: rgba(1, 170, 255, .375);--pvc-primary-inverse: #fff;--pvc-secondary: #969eaf;--pvc-secondary-background: #525f7a;--pvc-secondary-border: var(--pvc-secondary-background);--pvc-secondary-underline: rgba(150, 158, 175, .5);--pvc-secondary-hover: #b3b9c5;--pvc-secondary-hover-background: #5d6b89;--pvc-secondary-hover-border: var(--pvc-secondary-hover-background);--pvc-secondary-hover-underline: var(--pvc-secondary-hover);--pvc-secondary-focus: rgba(144, 158, 190, .25);--pvc-secondary-inverse: #fff;--pvc-contrast: #dfe3eb;--pvc-contrast-background: #eff1f4;--pvc-contrast-border: var(--pvc-contrast-background);--pvc-contrast-underline: rgba(223, 227, 235, .5);--pvc-contrast-hover: #fff;--pvc-contrast-hover-background: #fff;--pvc-contrast-hover-border: var(--pvc-contrast-hover-background);--pvc-contrast-hover-underline: var(--pvc-contrast-hover);--pvc-contrast-focus: rgba(207, 213, 226, .25);--pvc-contrast-inverse: #000;--pvc-box-shadow: .0145rem .029rem .174rem rgba(7, 8.5, 12, .01698), .0335rem .067rem .402rem rgba(7, 8.5, 12, .024), .0625rem .125rem .75rem rgba(7, 8.5, 12, .03), .1125rem .225rem 1.35rem rgba(7, 8.5, 12, .036), .2085rem .417rem 2.502rem rgba(7, 8.5, 12, .04302), .5rem 1rem 6rem rgba(7, 8.5, 12, .06), 0 0 0 .0625rem rgba(7, 8.5, 12, .015);--pvc-code-background-color: rgb(26, 30.5, 40.25);--pvc-code-color: #8891a4;--pvc-code-kbd-background-color: var(--pvc-color);--pvc-code-kbd-color: var(--pvc-background-color);--pvc-form-element-background-color: rgb(28, 33, 43.5);--pvc-form-element-selected-background-color: #2a3140;--pvc-form-element-border-color: #2a3140;--pvc-form-element-color: #e0e3e7;--pvc-form-element-placeholder-color: #8891a4;--pvc-form-element-active-background-color: rgb(26, 30.5, 40.25);--pvc-form-element-active-border-color: var(--pvc-primary-border);--pvc-form-element-focus-color: var(--pvc-primary-border);--pvc-form-element-disabled-opacity: .5;--pvc-form-element-invalid-border-color: rgb(149.5, 74, 80);--pvc-form-element-invalid-active-border-color: rgb(183.25, 63.5, 59);--pvc-form-element-invalid-focus-color: var(--pvc-form-element-invalid-active-border-color);--pvc-form-element-valid-border-color: #2a7b6f;--pvc-form-element-valid-active-border-color: rgb(22, 137, 105.5);--pvc-form-element-valid-focus-color: var(--pvc-form-element-valid-active-border-color);--pvc-switch-background-color: #333c4e;--pvc-switch-checked-background-color: var(--pvc-primary-background);--pvc-switch-color: #fff;--pvc-switch-thumb-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-range-border-color: #202632;--pvc-range-active-border-color: #2a3140;--pvc-range-thumb-border-color: var(--pvc-background-color);--pvc-range-thumb-color: var(--pvc-secondary-background);--pvc-range-thumb-active-color: var(--pvc-primary-background);--pvc-loading-spinner-opacity: .5;--pvc-icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pvc-icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}[data-theme=dark] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pvc-form-element-focus-color: var(--pvc-primary-focus)}[data-theme=dark] .pvc-settings-form [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline):before{filter:brightness(0)}.pvc-settings-form progress,.pvc-settings-form [type=checkbox],.pvc-settings-form [type=radio],.pvc-settings-form [type=range]{accent-color:var(--pvc-primary)}.pvc-settings-form :where(a:not([role=button])),.pvc-settings-form [role=link]{--pvc-color: var(--pvc-primary);--pvc-background-color: transparent;--pvc-underline: var(--pvc-primary-underline);outline:none;background-color:var(--pvc-background-color);color:var(--pvc-color);text-decoration:var(--pvc-text-decoration);text-decoration-color:var(--pvc-underline);text-underline-offset:.125em;transition:background-color var(--pvc-transition),color var(--pvc-transition),text-decoration var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form :where(a:not([role=button])):is([aria-current]:not([aria-current=false]),:hover,:active,:focus),.pvc-settings-form [role=link]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pvc-color: var(--pvc-primary-hover);--pvc-underline: var(--pvc-primary-hover-underline);--pvc-text-decoration: underline}.pvc-settings-form :where(a:not([role=button])):focus-visible,.pvc-settings-form [role=link]:focus-visible{box-shadow:0 0 0 var(--pvc-outline-width) var(--pvc-primary-focus)}.pvc-settings-form :where(a:not([role=button])).secondary,.pvc-settings-form [role=link].secondary{--pvc-color: var(--pvc-secondary);--pvc-underline: var(--pvc-secondary-underline)}.pvc-settings-form :where(a:not([role=button])).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),.pvc-settings-form [role=link].secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pvc-color: var(--pvc-secondary-hover);--pvc-underline: var(--pvc-secondary-hover-underline)}.pvc-settings-form :where(a:not([role=button])).contrast,.pvc-settings-form [role=link].contrast{--pvc-color: var(--pvc-contrast);--pvc-underline: var(--pvc-contrast-underline)}.pvc-settings-form :where(a:not([role=button])).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),.pvc-settings-form [role=link].contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pvc-color: var(--pvc-contrast-hover);--pvc-underline: var(--pvc-contrast-hover-underline)}.pvc-settings-form a[role=button]{display:inline-block}.pvc-settings-form pre,.pvc-settings-form code,.pvc-settings-form kbd,.pvc-settings-form samp{font-size:.875em;font-family:var(--pvc-font-family)}.pvc-settings-form pre code,.pvc-settings-form pre samp{font-size:inherit;font-family:inherit}.pvc-settings-form pre{-ms-overflow-style:scrollbar;overflow:auto}.pvc-settings-form pre,.pvc-settings-form code,.pvc-settings-form kbd,.pvc-settings-form samp{border-radius:var(--pvc-border-radius);background:var(--pvc-code-background-color);color:var(--pvc-code-color);font-weight:var(--pvc-font-weight);line-height:initial}.pvc-settings-form code,.pvc-settings-form kbd,.pvc-settings-form samp{display:inline-block;padding:.375rem}.pvc-settings-form pre{display:block;margin-bottom:var(--pvc-spacing);overflow-x:auto}.pvc-settings-form pre>code,.pvc-settings-form pre>samp{display:block;padding:var(--pvc-spacing);background:none;line-height:var(--pvc-line-height)}.pvc-settings-form kbd{background-color:var(--pvc-code-kbd-background-color);color:var(--pvc-code-kbd-color);vertical-align:baseline}.pvc-settings-form hr{height:0;margin:var(--pvc-typography-spacing-vertical) 0;border:0;border-top:1px solid var(--pvc-muted-border-color);color:inherit}.pvc-settings-form [hidden],.pvc-settings-form template{display:none!important}.pvc-settings-form canvas{display:inline-block}.pvc-settings-form input,.pvc-settings-form optgroup,.pvc-settings-form select,.pvc-settings-form textarea{margin:0;font-size:1rem;line-height:var(--pvc-line-height);font-family:inherit;letter-spacing:inherit}.pvc-settings-form input{overflow:visible}.pvc-settings-form select{text-transform:none}.pvc-settings-form legend{max-width:100%;padding:0;color:inherit;white-space:normal}.pvc-settings-form textarea{overflow:auto}.pvc-settings-form [type=checkbox],.pvc-settings-form [type=radio]{padding:0}.pvc-settings-form ::-webkit-inner-spin-button,.pvc-settings-form ::-webkit-outer-spin-button{height:auto}.pvc-settings-form [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.pvc-settings-form [type=search]::-webkit-search-decoration{-webkit-appearance:none}.pvc-settings-form ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.pvc-settings-form ::-moz-focus-inner{padding:0;border-style:none}.pvc-settings-form :-moz-focusring{outline:none}.pvc-settings-form :-moz-ui-invalid{box-shadow:none}.pvc-settings-form ::-ms-expand{display:none}.pvc-settings-form [type=file],.pvc-settings-form [type=range]{padding:0;border-width:0}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings-form fieldset{width:100%;margin:0;margin-bottom:var(--pvc-spacing);padding:0;border:0}.pvc-settings-form label,.pvc-settings-form fieldset legend{display:block;margin-bottom:calc(var(--pvc-spacing) * .375);color:var(--pvc-color);font-weight:var(--pvc-form-label-font-weight, var(--pvc-font-weight))}.pvc-settings-form fieldset legend{margin-bottom:calc(var(--pvc-spacing) * .5)}.pvc-settings-form input:not([type=checkbox],[type=radio]),.pvc-settings-form button[type=submit],.pvc-settings-form select,.pvc-settings-form textarea{width:100%}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file]),.pvc-settings-form select,.pvc-settings-form textarea{appearance:none;padding:var(--pvc-form-element-spacing-vertical) var(--pvc-form-element-spacing-horizontal)}.pvc-settings-form input,.pvc-settings-form select,.pvc-settings-form textarea{--pvc-background-color: var(--pvc-form-element-background-color);--pvc-border-color: var(--pvc-form-element-border-color);--pvc-color: var(--pvc-form-element-color);--pvc-box-shadow: none;border:var(--pvc-border-width) solid var(--pvc-border-color);border-radius:var(--pvc-border-radius);outline:none;background-color:var(--pvc-background-color);box-shadow:var(--pvc-box-shadow);color:var(--pvc-color);font-weight:var(--pvc-font-weight);transition:background-color var(--pvc-transition),border-color var(--pvc-transition),color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus),.pvc-settings-form :where(select,textarea):not([readonly]):is(:active,:focus){--pvc-background-color: var(--pvc-form-element-active-background-color)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus),.pvc-settings-form :where(select,textarea):not([readonly]):is(:active,:focus){--pvc-border-color: var(--pvc-form-element-active-border-color)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus,.pvc-settings-form :where(select,textarea):not([readonly]):focus{--pvc-box-shadow: 0 0 0 var(--pvc-outline-width) var(--pvc-form-element-focus-color)}.pvc-settings-form input:not([type=submit],[type=button],[type=reset])[disabled],.pvc-settings-form select[disabled],.pvc-settings-form textarea[disabled],.pvc-settings-form label[aria-disabled=true],.pvc-settings-form :where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea){opacity:var(--pvc-form-element-disabled-opacity);pointer-events:none}.pvc-settings-form label[aria-disabled=true] input[disabled]{opacity:1}.pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid]{padding-right:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--pvc-form-element-spacing-horizontal);padding-inline-start:var(--pvc-form-element-spacing-horizontal)!important;padding-inline-end:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}.pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=false]:not(select){background-image:var(--pvc-icon-valid)}.pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=true]:not(select){background-image:var(--pvc-icon-invalid)}.pvc-settings-form :where(input,select,textarea)[aria-invalid=false]{--pvc-border-color: var(--pvc-form-element-valid-border-color)}.pvc-settings-form :where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--pvc-border-color: var(--pvc-form-element-valid-active-border-color) !important}.pvc-settings-form :where(input,select,textarea)[aria-invalid=false]:is(:active,:focus):not([type=checkbox],[type=radio]){--pvc-box-shadow: 0 0 0 var(--pvc-outline-width) var(--pvc-form-element-valid-focus-color) !important}.pvc-settings-form :where(input,select,textarea)[aria-invalid=true]{--pvc-border-color: var(--pvc-form-element-invalid-border-color)}.pvc-settings-form :where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--pvc-border-color: var(--pvc-form-element-invalid-active-border-color) !important}.pvc-settings-form :where(input,select,textarea)[aria-invalid=true]:is(:active,:focus):not([type=checkbox],[type=radio]){--pvc-box-shadow: 0 0 0 var(--pvc-outline-width) var(--pvc-form-element-invalid-focus-color) !important}[dir=rtl] .pvc-settings-form :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}.pvc-settings-form input::placeholder,.pvc-settings-form input::-webkit-input-placeholder,.pvc-settings-form textarea::placeholder,.pvc-settings-form textarea::-webkit-input-placeholder,.pvc-settings-form select:invalid{color:var(--pvc-form-element-placeholder-color);opacity:1}.pvc-settings-form input:not([type=checkbox],[type=radio]),.pvc-settings-form select,.pvc-settings-form textarea{margin-bottom:var(--pvc-spacing)}.pvc-settings-form select::-ms-expand{border:0;background-color:transparent}.pvc-settings-form select:not([multiple],[size]){padding-right:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem);padding-left:var(--pvc-form-element-spacing-horizontal);padding-inline-start:var(--pvc-form-element-spacing-horizontal);padding-inline-end:calc(var(--pvc-form-element-spacing-horizontal) + 1.5rem);background-image:var(--pvc-icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}.pvc-settings-form select[multiple] option:checked{background:var(--pvc-form-element-selected-background-color);color:var(--pvc-form-element-color)}[dir=rtl] .pvc-settings-form select:not([multiple],[size]){background-position:center left .75rem}.pvc-settings-form textarea{display:block;resize:vertical}.pvc-settings-form textarea[aria-invalid]{--pvc-icon-height: calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2);background-position:top right .75rem!important;background-size:1rem var(--pvc-icon-height)!important}.pvc-settings-form :where(input,select,textarea,fieldset)+small{display:block;width:100%;margin-top:calc(var(--pvc-spacing) * -.75);margin-bottom:var(--pvc-spacing);color:var(--pvc-muted-color)}.pvc-settings-form :where(input,select,textarea,fieldset)[aria-invalid=false]+small{color:var(--pvc-ins-color)}.pvc-settings-form :where(input,select,textarea,fieldset)[aria-invalid=true]+small{color:var(--pvc-del-color)}.pvc-settings-form label>:where(input,select,textarea){margin-top:calc(var(--pvc-spacing) * .25)}.pvc-settings-form label:has([type=checkbox],[type=radio]){width:fit-content;cursor:pointer}.pvc-settings-form [type=checkbox],.pvc-settings-form [type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-inline-end:.5em;border-width:var(--pvc-border-width);vertical-align:middle;cursor:pointer}.pvc-settings-form [type=checkbox]::-ms-check,.pvc-settings-form [type=radio]::-ms-check{display:none}.pvc-settings-form [type=checkbox]:checked,.pvc-settings-form [type=checkbox]:checked:active,.pvc-settings-form [type=checkbox]:checked:focus,.pvc-settings-form [type=radio]:checked,.pvc-settings-form [type=radio]:checked:active,.pvc-settings-form [type=radio]:checked:focus{--pvc-background-color: var(--pvc-primary-background);--pvc-border-color: var(--pvc-primary-border);background-image:var(--pvc-icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}.pvc-settings-form [type=checkbox]~label,.pvc-settings-form [type=radio]~label{display:inline-block;margin-bottom:0;cursor:pointer}.pvc-settings-form [type=checkbox]~label:not(:last-of-type),.pvc-settings-form [type=radio]~label:not(:last-of-type){margin-inline-end:1em}.pvc-settings-form [type=checkbox]:indeterminate{--pvc-background-color: var(--pvc-primary-background);--pvc-border-color: var(--pvc-primary-border);background-image:var(--pvc-icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}.pvc-settings-form [type=radio]{border-radius:50%}.pvc-settings-form [type=radio]:checked,.pvc-settings-form [type=radio]:checked:active,.pvc-settings-form [type=radio]:checked:focus{--pvc-background-color: var(--pvc-primary-inverse);border-width:.35em;background-image:none}.pvc-settings-form [type=checkbox][role=switch]{--pvc-background-color: var(--pvc-switch-background-color);--pvc-color: var(--pvc-switch-color);width:2.25em;height:1.25em;border:var(--pvc-border-width) solid var(--pvc-border-color);border-radius:1.25em;background-color:var(--pvc-background-color);line-height:1.25em}.pvc-settings-form [type=checkbox][role=switch]:not([aria-invalid]){--pvc-border-color: var(--pvc-switch-background-color)}.pvc-settings-form [type=checkbox][role=switch]:before{display:block;aspect-ratio:1;height:100%;border-radius:50%;background-color:var(--pvc-color);box-shadow:var(--pvc-switch-thumb-box-shadow);content:"";transition:margin .1s ease-in-out}.pvc-settings-form [type=checkbox][role=switch]:focus{--pvc-background-color: var(--pvc-switch-background-color);--pvc-border-color: var(--pvc-switch-background-color)}.pvc-settings-form [type=checkbox][role=switch]:checked{--pvc-background-color: var(--pvc-switch-checked-background-color);--pvc-border-color: var(--pvc-switch-checked-background-color);background-image:none}.pvc-settings-form [type=checkbox][role=switch]:checked:before{margin-inline-start:1em}.pvc-settings-form [type=checkbox][role=switch][disabled]{--pvc-background-color: var(--pvc-border-color)}.pvc-settings-form [type=checkbox][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:focus,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:focus{--pvc-background-color: var(--pvc-form-element-valid-border-color)}.pvc-settings-form [type=checkbox]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:focus[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:focus[aria-invalid=true]{--pvc-background-color: var(--pvc-form-element-invalid-border-color)}.pvc-settings-form [type=checkbox][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][aria-invalid=false]:checked:focus,.pvc-settings-form [type=radio][aria-invalid=false]:checked,.pvc-settings-form [type=radio][aria-invalid=false]:checked:active,.pvc-settings-form [type=radio][aria-invalid=false]:checked:focus,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:active,.pvc-settings-form [type=checkbox][role=switch][aria-invalid=false]:checked:focus{--pvc-border-color: var(--pvc-form-element-valid-border-color)}.pvc-settings-form [type=checkbox]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox]:checked:focus[aria-invalid=true],.pvc-settings-form [type=radio]:checked[aria-invalid=true],.pvc-settings-form [type=radio]:checked:active[aria-invalid=true],.pvc-settings-form [type=radio]:checked:focus[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:active[aria-invalid=true],.pvc-settings-form [type=checkbox][role=switch]:checked:focus[aria-invalid=true]{--pvc-border-color: var(--pvc-form-element-invalid-border-color)}.pvc-settings-form [type=color]::-webkit-color-swatch-wrapper{padding:0}.pvc-settings-form [type=color]::-moz-focus-inner{padding:0}.pvc-settings-form [type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--pvc-border-radius) * .5)}.pvc-settings-form [type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--pvc-border-radius) * .5)}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--pvc-icon-position: .75rem;--pvc-icon-width: 1rem;padding-right:calc(var(--pvc-icon-width) + var(--pvc-icon-position));background-image:var(--pvc-icon-date);background-position:center right var(--pvc-icon-position);background-size:var(--pvc-icon-width) auto;background-repeat:no-repeat}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--pvc-icon-time)}.pvc-settings-form [type=date]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=datetime-local]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=month]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=time]::-webkit-calendar-picker-indicator,.pvc-settings-form [type=week]::-webkit-calendar-picker-indicator{width:var(--pvc-icon-width);margin-right:calc(var(--pvc-icon-width) * -1);margin-left:var(--pvc-icon-position);opacity:0}@-moz-document url-prefix(){.pvc-settings-form [type=date],.pvc-settings-form [type=datetime-local],.pvc-settings-form [type=month],.pvc-settings-form [type=time],.pvc-settings-form [type=week]{padding-right:var(--pvc-form-element-spacing-horizontal)!important;background-image:none!important}}[dir=rtl] .pvc-settings-form :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}.pvc-settings-form [type=file]{--pvc-color: var(--pvc-muted-color);margin-left:calc(var(--pvc-outline-width) * -1);padding:calc(var(--pvc-form-element-spacing-vertical) * .5) 0;padding-left:var(--pvc-outline-width);border:0;border-radius:0;background:none}.pvc-settings-form [type=file]::file-selector-button{margin-right:calc(var(--pvc-spacing) / 2);padding:calc(var(--pvc-form-element-spacing-vertical) * .5) var(--pvc-form-element-spacing-horizontal)}.pvc-settings-form [type=file]:is(:hover,:active,:focus)::file-selector-button{--pvc-background-color: var(--pvc-secondary-hover-background);--pvc-border-color: var(--pvc-secondary-hover-border)}.pvc-settings-form [type=file]:focus::file-selector-button{--pvc-box-shadow: var(--pvc-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)), 0 0 0 var(--pvc-outline-width) var(--pvc-secondary-focus)}.pvc-settings-form [type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:none}.pvc-settings-form [type=range]::-webkit-slider-runnable-track{width:100%;height:.375rem;border-radius:var(--pvc-border-radius);background-color:var(--pvc-range-border-color);transition:background-color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form [type=range]::-moz-range-track{width:100%;height:.375rem;border-radius:var(--pvc-border-radius);background-color:var(--pvc-range-border-color);transition:background-color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form [type=range]::-ms-track{width:100%;height:.375rem;border-radius:var(--pvc-border-radius);background-color:var(--pvc-range-border-color);transition:background-color var(--pvc-transition),box-shadow var(--pvc-transition)}.pvc-settings-form [type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pvc-range-thumb-border-color);border-radius:50%;background-color:var(--pvc-range-thumb-color);cursor:pointer;transition:background-color var(--pvc-transition),transform var(--pvc-transition)}.pvc-settings-form [type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pvc-range-thumb-border-color);border-radius:50%;background-color:var(--pvc-range-thumb-color);cursor:pointer;transition:background-color var(--pvc-transition),transform var(--pvc-transition)}.pvc-settings-form [type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pvc-range-thumb-border-color);border-radius:50%;background-color:var(--pvc-range-thumb-color);cursor:pointer;transition:background-color var(--pvc-transition),transform var(--pvc-transition)}.pvc-settings-form [type=range]:active,.pvc-settings-form [type=range]:focus-within{--pvc-range-border-color: var(--pvc-range-active-border-color);--pvc-range-thumb-color: var(--pvc-range-thumb-active-color)}.pvc-settings-form [type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}.pvc-settings-form [type=range]:active::-moz-range-thumb{transform:scale(1.25)}.pvc-settings-form [type=range]:active::-ms-thumb{transform:scale(1.25)}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{padding-inline-start:calc(var(--pvc-form-element-spacing-horizontal) + 1.75rem);background-image:var(--pvc-icon-search);background-position:center left calc(var(--pvc-form-element-spacing-horizontal) + .125rem);background-size:1rem auto;background-repeat:no-repeat}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{padding-inline-start:calc(var(--pvc-form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--pvc-icon-search),var(--pvc-icon-valid)}.pvc-settings-form input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--pvc-icon-search),var(--pvc-icon-invalid)}[dir=rtl] .pvc-settings-form :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] .pvc-settings-form :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}.pvc-settings-form [role=search],.pvc-settings-form [role=group]{display:inline-flex;position:relative;width:100%;margin-bottom:var(--pvc-spacing);border-radius:var(--pvc-border-radius);box-shadow:var(--pvc-group-box-shadow, 0 0 0 rgba(0, 0, 0, 0));vertical-align:middle;transition:box-shadow var(--pvc-transition)}.pvc-settings-form [role=search]>*,.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=search] select,.pvc-settings-form [role=group]>*,.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=group] select{position:relative;flex:1 1 auto;margin-bottom:0}.pvc-settings-form [role=search]>*:not(:first-child),.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=search] select:not(:first-child),.pvc-settings-form [role=group]>*:not(:first-child),.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=group] select:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.pvc-settings-form [role=search]>*:not(:last-child),.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):not(:last-child),.pvc-settings-form [role=search] select:not(:last-child),.pvc-settings-form [role=group]>*:not(:last-child),.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):not(:last-child),.pvc-settings-form [role=group] select:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.pvc-settings-form [role=search]>*:focus,.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):focus,.pvc-settings-form [role=search] select:focus,.pvc-settings-form [role=group]>*:focus,.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):focus,.pvc-settings-form [role=group] select:focus{z-index:2}.pvc-settings-form [role=search] button:not(:first-child),.pvc-settings-form [role=search] [type=submit]:not(:first-child),.pvc-settings-form [role=search] [type=reset]:not(:first-child),.pvc-settings-form [role=search] [type=button]:not(:first-child),.pvc-settings-form [role=search] [role=button]:not(:first-child),.pvc-settings-form [role=search] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=search] select:not(:first-child),.pvc-settings-form [role=group] button:not(:first-child),.pvc-settings-form [role=group] [type=submit]:not(:first-child),.pvc-settings-form [role=group] [type=reset]:not(:first-child),.pvc-settings-form [role=group] [type=button]:not(:first-child),.pvc-settings-form [role=group] [role=button]:not(:first-child),.pvc-settings-form [role=group] input:not([type=checkbox],[type=radio]):not(:first-child),.pvc-settings-form [role=group] select:not(:first-child){margin-left:calc(var(--pvc-border-width) * -1)}.pvc-settings-form [role=search] button,.pvc-settings-form [role=search] [type=submit],.pvc-settings-form [role=search] [type=reset],.pvc-settings-form [role=search] [type=button],.pvc-settings-form [role=search] [role=button],.pvc-settings-form [role=group] button,.pvc-settings-form [role=group] [type=submit],.pvc-settings-form [role=group] [type=reset],.pvc-settings-form [role=group] [type=button],.pvc-settings-form [role=group] [role=button]{width:auto}@supports selector(:has(*)){.pvc-settings-form [role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus),.pvc-settings-form [role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus){--pvc-group-box-shadow: var(--pvc-group-box-shadow-focus-with-button)}.pvc-settings-form [role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select,.pvc-settings-form [role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),.pvc-settings-form [role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select{border-color:transparent}.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus),.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus){--pvc-group-box-shadow: var(--pvc-group-box-shadow-focus-with-input)}.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) button,.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],.pvc-settings-form [role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) button,.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],.pvc-settings-form [role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button]{--pvc-button-box-shadow: 0 0 0 var(--pvc-border-width) var(--pvc-primary-border);--pvc-button-hover-box-shadow: 0 0 0 var(--pvc-border-width) var(--pvc-primary-hover-border)}.pvc-settings-form [role=search] button:focus,.pvc-settings-form [role=search] [type=submit]:focus,.pvc-settings-form [role=search] [type=reset]:focus,.pvc-settings-form [role=search] [type=button]:focus,.pvc-settings-form [role=search] [role=button]:focus,.pvc-settings-form [role=group] button:focus,.pvc-settings-form [role=group] [type=submit]:focus,.pvc-settings-form [role=group] [type=reset]:focus,.pvc-settings-form [role=group] [type=button]:focus,.pvc-settings-form [role=group] [role=button]:focus{box-shadow:none}}.pvc-settings-form [role=search]>*:first-child{border-top-left-radius:5rem;border-bottom-left-radius:5rem}.pvc-settings-form [role=search]>*:last-child{border-top-right-radius:5rem;border-bottom-right-radius:5rem}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form){white-space:nowrap}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form):before{display:inline-block;width:1em;height:1em;background-image:var(--pvc-icon-loading);background-size:1em auto;background-repeat:no-repeat;content:"";vertical-align:-.125em}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form):not(:empty):before{margin-inline-end:calc(var(--pvc-spacing) * .5)}.pvc-settings-form [aria-busy=true]:not(input,select,textarea,html,form):empty{text-align:center}.pvc-settings-form button[aria-busy=true],.pvc-settings-form [type=submit][aria-busy=true],.pvc-settings-form [type=button][aria-busy=true],.pvc-settings-form [type=reset][aria-busy=true],.pvc-settings-form [role=button][aria-busy=true],.pvc-settings-form a[aria-busy=true]{pointer-events:none}.pvc-settings-form [aria-controls]{cursor:pointer}.pvc-settings-form [aria-disabled=true],.pvc-settings-form [disabled]{cursor:not-allowed}.pvc-settings-form [aria-hidden=false][hidden]{display:initial}.pvc-settings-form [aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}.pvc-settings-form a,.pvc-settings-form area,.pvc-settings-form button,.pvc-settings-form input,.pvc-settings-form label,.pvc-settings-form select,.pvc-settings-form summary,.pvc-settings-form textarea,.pvc-settings-form [tabindex]{-ms-touch-action:manipulation}.pvc-settings-form [dir=rtl]{direction:rtl}.pvc-settings-wrapper{--pvc-theme-color: var(--wp-admin-theme-color, #2271b1);--pvc-theme-color-rgb: var(--wp-admin-theme-color--rgb, 34, 113, 177);--pvc-theme-color-darker-10: var(--wp-admin-theme-color-darker-10, #135e96);--pvc-border-width-focus: var(--wp-admin-border-width-focus, 2px);--pvc-surface: #fff;--pvc-surface-muted: #ebebeb;--pvc-text: #3c434a;--pvc-text-strong: #070707;--pvc-text-input: #2c3338;--pvc-text-muted: #757575;--pvc-border: #c3c4c7;--pvc-border-input: #8c8f94;--pvc-button-bg: #f6f7f7;--pvc-button-bg-hover: #f0f0f1;--pvc-button-border: #8c8f94;--pvc-button-border-hover: #757575;--pvc-button-text: #2c3338;--pvc-button-text-hover: #070707;--pvc-button-focus: var(--pvc-theme-color);--pvc-font-family-emoji: inherit;--pvc-font-family-sans-serif: inherit;--pvc-font-family-monospace: inherit;--pvc-font-family: var(--pvc-font-family-sans-serif);--pvc-line-height: 1.5;--pvc-font-weight: 400;--pvc-font-size: 100%;--pvc-text-underline-offset: .1rem;--pvc-border-radius: .25rem;--pvc-border-width: .0625rem;--pvc-outline-width: .125rem;--pvc-transition: .2s ease-in-out;--pvc-spacing: 1rem;--pvc-typography-spacing-vertical: 1rem;--pvc-block-spacing-vertical: 20px;--pvc-block-spacing-horizontal: 20px;--pvc-grid-column-gap: 20px;--pvc-grid-row-gap: 20px;--pvc-form-element-spacing-vertical: .45rem;--pvc-form-element-spacing-horizontal: .8rem;--pvc-form-element-disabled-opacity: .6;--pvc-group-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--pvc-group-box-shadow-focus-with-button: 0 0 0 var(--pvc-outline-width) var(--pvc-primary-focus);--pvc-group-box-shadow-focus-with-input: 0 0 0 .0625rem var(--pvc-form-element-border-color);--pvc-modal-overlay-backdrop-filter: blur(.375rem);--pvc-nav-element-spacing-vertical: 1rem;--pvc-nav-element-spacing-horizontal: .5rem;--pvc-nav-link-spacing-vertical: .5rem;--pvc-nav-link-spacing-horizontal: .5rem;--pvc-nav-breadcrumb-divider: ">";--pvc-primary: var(--pvc-theme-color);--pvc-primary-background: var(--pvc-theme-color);--pvc-primary-border: var(--pvc-theme-color);--pvc-primary-underline: rgba(var(--pvc-theme-color-rgb), .5);--pvc-primary-hover: var(--pvc-theme-color-darker-10);--pvc-primary-hover-background: var(--pvc-theme-color-darker-10);--pvc-primary-hover-border: var(--pvc-theme-color-darker-10);--pvc-primary-hover-underline: var(--pvc-theme-color-darker-10);--pvc-primary-focus: rgba(var(--pvc-theme-color-rgb), .25);--pvc-primary-inverse: #fff;--pvc-secondary: var(--pvc-button-text);--pvc-secondary-background: var(--pvc-button-bg);--pvc-secondary-border: var(--pvc-button-border);--pvc-secondary-underline: rgba(var(--pvc-theme-color-rgb), .4);--pvc-secondary-hover: var(--pvc-button-text-hover);--pvc-secondary-hover-background: var(--pvc-button-bg-hover);--pvc-secondary-hover-border: var(--pvc-button-border-hover);--pvc-secondary-hover-underline: var(--pvc-button-border-hover);--pvc-secondary-focus: var(--pvc-button-focus);--pvc-secondary-inverse: var(--pvc-button-text);--pvc-contrast: var(--pvc-text-strong);--pvc-contrast-background: var(--pvc-text-strong);--pvc-contrast-border: var(--pvc-text-strong);--pvc-contrast-hover: #000;--pvc-contrast-hover-background: #000;--pvc-contrast-hover-border: #000;--pvc-contrast-focus: rgba(var(--pvc-theme-color-rgb), .25);--pvc-contrast-inverse: #fff;color-scheme:light;--pvc-background-color: var(--pvc-surface);--pvc-color: var(--pvc-text);--pvc-muted-color: var(--pvc-text-muted);--pvc-muted-border-color: var(--pvc-border);--pvc-box-shadow: 0 1px 1px rgba(0, 0, 0, .04);--pvc-text-selection-color: rgba(var(--pvc-theme-color-rgb), .25);--pvc-table-border-color: var(--pvc-border);--pvc-table-row-stripped-background-color: var(--pvc-surface-muted);--pvc-form-element-background-color: var(--pvc-surface);--pvc-form-element-active-background-color: var(--pvc-surface);--pvc-form-element-selected-background-color: var(--pvc-surface-muted);--pvc-form-element-border-color: var(--pvc-border-input);--pvc-form-element-color: var(--pvc-text-input);--pvc-form-element-placeholder-color: var(--pvc-text-muted);--pvc-form-element-active-border-color: var(--pvc-theme-color);--pvc-form-element-focus-color: var(--pvc-theme-color);--pvc-switch-background-color: var(--pvc-border-input);--pvc-switch-checked-background-color: var(--pvc-theme-color);--pvc-switch-color: #fff;--pvc-outline-width: var(--pvc-border-width-focus);--pvc-block-spacing: var(--pvc-block-spacing-vertical) var(--pvc-block-spacing-horizontal);--pvc-form-element-spacing: var(--pvc-form-element-spacing-vertical) var(--pvc-form-element-spacing-horizontal);--pvc-typography-spacing: var(--pvc-typography-spacing-vertical)}.pvc-settings-wrapper .button.button-secondary{--pvc-primary: var(--pvc-secondary);--pvc-primary-background: var(--pvc-secondary-background);--pvc-primary-border: var(--pvc-secondary-border);--pvc-primary-hover: var(--pvc-secondary-hover);--pvc-primary-hover-background: var(--pvc-secondary-hover-background);--pvc-primary-hover-border: var(--pvc-secondary-hover-border);--pvc-primary-hover-underline: var(--pvc-secondary-hover-underline);--pvc-primary-focus: var(--pvc-secondary-focus);--pvc-primary-inverse: var(--pvc-secondary-inverse)}.pvc-settings-wrapper code,.pvc-settings-wrapper kbd,.pvc-settings-wrapper samp{background:#f0f0f1;background:#00000012;color:var(--pvc-text)}.wp-admin #wpcontent{padding:0}.wp-admin #wpbody-content>.notice,.wp-admin #wpbody-content>.error,.wp-admin #wpbody-content>.updated,.wp-admin #wpbody-content>.info{display:none}.wp-admin .wrap{margin:0}.pvc-settings-wrapper .header-wrapper{padding:20px 40px;background-color:var(--pvc-surface);border-bottom:1px solid var(--pvc-surface-muted)}.pvc-settings-wrapper .content-wrapper{padding:0 40px}.pvc-settings-wrapper .header-title{font-weight:600;font-size:18px;line-height:1;color:var(--pvc-text-strong)}.pvc-settings-wrapper .nav-tab-wrapper{display:flex;flex-wrap:wrap;list-style:none;padding:10px 40px 0;gap:30px;margin:0 0 20px;background:var(--pvc-surface);border-bottom:1px solid var(--pvc-surface-muted)}.pvc-settings-wrapper .nav-tab-wrapper .nav-tab{margin:2px 0 0;border:0;background:none;font-weight:600;font-size:14px;line-height:20px;padding:0 0 10px;text-decoration:none;border-bottom:2px solid transparent}.pvc-settings-wrapper .nav-tab-wrapper .nav-tab:hover,.pvc-settings-wrapper .nav-tab-wrapper .nav-tab:focus{color:var(--wp-admin-theme-color);outline:none;box-shadow:none}.pvc-settings-wrapper .nav-tab-wrapper .nav-tab.nav-tab-active{border-bottom-color:var(--wp-admin-theme-color)}.pvc-settings form{min-width:463px;width:auto;flex:1 1 auto}.pvc-settings form input[type=radio]:checked{background-color:var(--pvc-form-element-background-color)}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]){width:auto;min-width:80px;max-width:100%;font-size:var(--pvc-font-size);line-height:var(--pvc-line-height);border-radius:var(--pvc-border-radius);margin-bottom:0;padding:var(--pvc-form-element-spacing-vertical) var(--pvc-form-element-spacing-horizontal);min-height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]).large-text{width:100%}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]).regular-text{width:25rem}.pvc-settings input:not([type=checkbox],[type=radio],[type=submit],[type=reset],[type=button]).small-text{width:8rem}.pvc-settings [type=search]{--pvc-border-radius: .25rem}.pvc-settings select,.pvc-settings textarea{width:auto;max-width:100%;font-size:var(--pvc-font-size);line-height:var(--pvc-line-height);margin-bottom:0}.pvc-settings select{width:25rem;min-height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings [type=submit].button,.pvc-settings [type=button].button{width:auto;font-size:var(--pvc-font-size);line-height:var(--pvc-line-height);border-radius:var(--pvc-border-radius);min-height:calc(1rem * var(--pvc-line-height) + var(--pvc-form-element-spacing-vertical) * 2 + var(--pvc-border-width) * 2)}.pvc-settings [type=submit].button.button-small,.pvc-settings [type=button].button.button-small{font-size:calc(var(--pvc-font-size) * .875);height:auto}.pvc-settings span[role=button]{background:none;border:none;padding:0;margin:0;font-size:inherit}.pvc-settings .submit{display:flex;gap:10px}.pvc-settings .pvc-sidebar{width:300px;flex:0 0 300px;margin-left:20px}.pvc-settings.has-sidebar{display:flex;justify-content:space-between}@media(max-width:960px){.pvc-settings.has-sidebar{flex-direction:column}.pvc-settings form{width:100%}.pvc-settings .pvc-sidebar{width:100%;flex:0 0 auto;margin-left:0;margin-top:20px}}.pvc-settings p.help,.pvc-settings p.description,.pvc-settings span.description{font-size:13px;font-style:italic;color:var(--pvc-text-muted)}.pvc-range-field{display:flex;gap:10px;align-items:center}.pvc-range-field input[type=range]{appearance:none;color-scheme:light;background:transparent;accent-color:var(--pvc-theme-color)}.pvc-range-field input[type=range]::-webkit-slider-runnable-track{height:4px;background:#dcdcde;border-radius:999px}.pvc-range-field input[type=range]::-webkit-slider-thumb{appearance:none;width:16px;height:16px;margin-top:-6px;border-radius:50%;background:var(--pvc-theme-color);border:1px solid var(--pvc-theme-color)}.pvc-range-field input[type=range]::-moz-range-track{height:4px;background:#dcdcde;border-radius:999px}.pvc-range-field input[type=range]::-moz-range-progress{height:4px;background:var(--pvc-theme-color);border-radius:999px}.pvc-range-field input[type=range]::-moz-range-thumb{width:16px;height:16px;border-radius:50%;background:var(--pvc-theme-color);border:1px solid var(--pvc-theme-color)}.pvc-buttons-group{display:flex;gap:10px}.pvc-buttons-group [type=submit].button,.pvc-buttons-group [type=button].button{margin:0}.pvc-field-group label{margin-right:10px}.pvc-field-group.horizontal label{display:inline-block}.pvc-field-group.vertical label{display:block;margin-bottom:8px}.pvc-field input[type=checkbox]:checked:not([role=switch]):before,.pvc-field input[type=radio]:checked:before{display:none}.pvc-field input[type=checkbox][role=switch]:checked:before{width:auto;margin-top:0;margin-bottom:0}.pvc-disabled{opacity:var(--pvc-form-element-disabled-opacity);cursor:not-allowed}.pvc-disabled [type=radio]{border-color:var(--pvc-form-element-border-color)}.pvc-disabled select[disabled]{opacity:1}.pvc-field-type-color .pvc-color-control{display:flex;gap:10px;align-items:center;position:relative;width:fit-content}.pvc-field-type-color .pvc-color-control button{margin-bottom:0}.pvc-field-type-color .pvc-color-input{min-width:8rem}.pvc-field-type-color .pvc-color-swatch{width:32px;height:32px;padding:0;border-radius:var(--pvc-border-radius);border:1px solid var(--pvc-form-element-border-color);box-shadow:inset 0 0 0 2px var(--pvc-form-element-background-color);cursor:pointer;flex-shrink:0}.pvc-field-type-color .pvc-color-swatch:focus{outline:none;box-shadow:inset 0 0 0 2px var(--pvc-form-element-background-color),0 0 0 2px var(--pvc-form-element-focus-color)}.pvc-field-type-color .pvc-color-popover{position:absolute;top:calc(100% + 6px);left:0;padding:8px;border-radius:var(--pvc-border-radius);border:1px solid var(--pvc-form-element-border-color);background:var(--pvc-form-element-background-color);box-shadow:0 6px 18px #0000001f;z-index:1000;display:none;pointer-events:auto}.pvc-field-type-color.is-open .pvc-color-popover{display:block}.pvc-field-type-color hex-color-picker{width:200px;height:200px;pointer-events:auto}.pvc-checkbox-group label:has(input:disabled),.pvc-radio-group label:has(input:disabled){opacity:var(--pvc-form-element-disabled-opacity);cursor:not-allowed}.pvc-hidden{display:none!important}@keyframes pvc-fade-in{0%{opacity:0}to{opacity:1}}@keyframes pvc-fade-out{0%{opacity:1}to{opacity:0}}@keyframes pvc-slide-in{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes pvc-slide-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-10px)}}.pvc-anim-in,.pvc-anim-out{animation-duration:var(--pvc-animation-duration, .25s);animation-fill-mode:both}.pvc-anim-fade.pvc-anim-in{animation-name:pvc-fade-in}.pvc-anim-fade.pvc-anim-out{animation-name:pvc-fade-out}.pvc-anim-slide.pvc-anim-in{animation-name:pvc-slide-in}.pvc-anim-slide.pvc-anim-out{animation-name:pvc-slide-out}.post-views-counter-settings.has-sidebar{display:flex;flex-direction:row;gap:30px;justify-content:space-between}.post-views-counter-settings form{min-width:463px;width:auto;position:relative}.post-views-counter-settings p.help,.post-views-counter-settings p.description{font-size:13px;font-style:italic;line-height:1.6}.post-views-counter-settings .pvc-template-tags-list{display:block;margin-top:5px;font-style:normal}.post-views-counter-settings select{vertical-align:top;width:auto}.post-views-counter-settings .available{color:#00a32a}.post-views-counter-settings .unavailable{color:#d63638}.post-views-counter-settings .pvc-ip-box-group{margin-bottom:10px}.post-views-counter-settings .pvc-ip-box{margin-bottom:5px}.post-views-counter-settings .pvc-button{color:#fff;background-color:#6610f2;border-color:#6610f2;border-radius:.25rem}.post-views-counter-settings .pvc-button:active,.post-views-counter-settings .pvc-button:focus,.post-views-counter-settings .pvc-button:hover{color:#fff;background-color:#570ece;border-color:#570ece}.post-views-counter-settings .pvc-button:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #6610f2}.post-views-counter-settings tr.pvc-pro th:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600}.post-views-counter-settings label.pvc-pro:after{content:"PRO";display:inline-block;margin-left:6px;padding:1px 4px;font-size:11px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600;font-style:normal}.post-views-sidebar{margin:15px 0;position:relative;order:1}.post-views-sidebar>div:not(:last-child){margin-bottom:3em}.post-views-sidebar .inner{padding:1.5em}.post-views-sidebar .inner img{max-width:80%;height:auto;display:block;margin:20px auto}.pvc-status-table .pvc-status{display:inline-block}.pvc-status-table .pvc-status-active{color:#00a32a}.pvc-status-table .pvc-status-missing{color:#d63638}.pvc-subfield{margin-top:12px}.is-hidden{display:none!important;visibility:hidden!important}output{display:block;font-size:30px;font-weight:700;text-align:center;margin:30px 0;width:100%}.post-views-credits{background:#fff;box-shadow:0 0 0 1px #0000000d}.post-views-credits .inner{text-align:center;margin:0}.post-views-credits p:first-child{margin-top:0}.post-views-credits .pvc-sidebar-title{font-size:17px;font-weight:700;margin:.5rem 0 1rem}.post-views-credits .pvc-sidebar-title:after{content:"PRO";display:inline-block;margin-left:6px;padding:0 4px 1px;font-size:14px;border-radius:4px;background-color:#ffc107;color:#fff;font-weight:600}.post-views-credits .pvc-sidebar-subtitle{font-size:15px;font-weight:600;color:#1d2327;text-align:center;margin:1rem 0 1.5rem}.post-views-credits .pvc-sidebar-one-liner{text-align:center;margin-top:1.5rem}.post-views-credits .pvc-sidebar-body{font-size:14px;text-align:left;margin:1.5rem 0 2rem;padding:0}.post-views-credits .pvc-sidebar-body p{font-size:inherit;padding-left:20px;margin:.75rem 0;position:relative}.post-views-credits .pvc-sidebar-body b{color:#000}.post-views-credits .pvc-sidebar-body .pvc-icon{position:absolute;top:1px;left:0}.post-views-credits .pvc-sidebar-body .pvc-icon-check{box-sizing:border-box;display:block;transform:scale(1);width:16px;height:22px;border-radius:100px}.post-views-credits .pvc-sidebar-body .pvc-icon-check:after{content:"";display:block;box-sizing:border-box;position:absolute;left:0;top:0;width:6px;height:10px;border-width:0 2px 2px 0;border-style:solid;transform-origin:bottom left;transform:rotate(45deg)}#post_views_counter_other_license_setting .pvc-status-icon{vertical-align:middle;margin-left:8px;padding-bottom:3px}#post_views_counter_other_license_setting .pvc-status-icon:before{content:"\2717";color:#d63638}#post_views_counter_other_license_setting.license-status .pvc-status-icon:before{content:"\2717";color:#d63638}#post_views_counter_other_license_setting.license-status.valid .pvc-status-icon:before{content:"\2713";color:#00a32a}#pvc-reports-upgrade{position:absolute;left:0;top:0;height:100%;width:100%;overflow:hidden;box-sizing:border-box;min-height:400px}#pvc-reports-upgrade #pvc-reports-modal{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);padding:1.5em 3em;box-shadow:0 0 25px 10px #0000001a;border-radius:3px;background-color:#fff;text-align:center;width:26em}#pvc-reports-upgrade #pvc-reports-modal p{margin:0}#pvc-reports-upgrade #pvc-reports-modal h2{font-size:21px;font-weight:400;margin:0 0 10px;padding:9px 0 4px;line-height:1.3}#pvc-reports-upgrade #pvc-reports-modal .button{margin-top:25px;margin-bottom:10px}#pvc-reports-bg{width:100%;height:auto;opacity:.8;filter:blur(2px)}@media only screen and (max-width:960px){.post-views-counter-settings{flex-wrap:wrap}.post-views-counter-settings .post-views-sidebar{width:100%}}@media only screen and (max-width:782px){.post-views-counter-settings .pvc-settings-form{min-width:0}.post-views-counter-settings .form-table{table-layout:fixed}.post-views-counter-settings .form-table td input.regular-text,.post-views-counter-settings .form-table td select,.post-views-counter-settings .form-table td textarea{width:100%;max-width:100%}}.pvc-provider-radio{display:inline-block;margin-right:20px;font-weight:400}.pvc-provider-radio input[type=radio]{margin-right:5px}.pvc-provider-content{margin:0}.pvc-provider-fields{padding:0;margin-top:15px}.pvc-provider-fields label{font-weight:600;margin-bottom:5px;display:block}.pvc-provider-fields input.regular-text{margin-top:5px}.pvc-provider-unavailable{color:#d63638;font-style:italic}.pvc-import-strategy{margin-bottom:25px}.pvc-field>label{margin-bottom:0}.pvc-field-group label{margin-right:8px}.pvc-radio-vertical label{display:block;margin:6px 0;font-weight:400}.pvc-radio-vertical input[type=radio]{margin-right:5px}.pvc-import-actions{padding-top:10px}.pvc-import-actions .button{margin-right:10px}.pvc-import-actions .button-primary{font-weight:600}.pvc-integration-content.unavailable{color:inherit;pointer-events:none}.pvc-integration-content.unavailable .pvc-integration-items{display:none}.pvc-integration-content input[type=checkbox]{margin-right:10px}.pvc-integration-content label{display:block;cursor:pointer}.pvc-integration-content .pvc-integration-items{margin:15px 0 0;padding-left:13px;font-size:13px;font-style:italic}.pvc-integration-content .pvc-integration-items li{margin-bottom:5px;list-style:disc}.pvc-integration-content .pvc-integration-items li:last-child{margin-bottom:0}.mce-container[role=group]{margin:0;display:block} -
post-views-counter/tags/1.8.0/css/block-editor.css
r3647380 r3734102 1 .edit-post-post-views{gap:8px;margin-top:0}.edit-post-post-views- popover .components-popover__content{padding:10px;min-width:260px}.edit-post-post-views-popover .components-popover__content legend{font-weight:600;margin-bottom:1em;margin-top:.5em;padding:0}.components-button:has(.pvc-icon){pointer-events:none;cursor:default;position:relative}.components-button:has(.pvc-icon) span.components-truncate{opacity:.5}.components-button:has(.pvc-icon) .pvc-icon svg{opacity:.5}.pvc-icon{position:relative;display:inline-flex}.pvc-icon__badge{position:absolute;bottom:-2px;right:-4px;font-size:9px;font-weight:600;line-height:1;color:#fff;background-color:#ffc107;border-radius:2px;padding:1px 2px 2px}1 .edit-post-post-views{gap:8px;margin-top:0}.edit-post-post-views-value{display:inline-block;padding:0 8px;line-height:32px}.edit-post-post-views-popover .components-popover__content{padding:10px;min-width:260px}.edit-post-post-views-popover .components-popover__content .edit-post-post-views-popover-content{display:flex;flex-direction:column;align-items:flex-start;gap:8px}.edit-post-post-views-popover .components-popover__content .edit-post-post-views-popover-content .components-base-control{width:100%}.edit-post-post-views-popover .components-popover__content .edit-post-post-views-popover-content .description{margin:0}.components-button:has(.pvc-icon){pointer-events:none;cursor:default;position:relative}.components-button:has(.pvc-icon) span.components-truncate{opacity:.5}.components-button:has(.pvc-icon) .pvc-icon svg{opacity:.5}.pvc-icon{position:relative;display:inline-flex}.pvc-icon__badge{position:absolute;bottom:-2px;right:-4px;font-size:9px;font-weight:600;line-height:1;color:#fff;background-color:#ffc107;border-radius:2px;padding:1px 2px 2px} -
post-views-counter/tags/1.8.0/css/frontend.css
r3640258 r3734102 1 .p ost-views.entry-meta>span{margin-right:0!important;font:16px/1}.post-views.entry-meta>span.post-views-icon.dashicons{display:inline-block;font-size:16px;line-height:1;text-decoration:inherit;vertical-align:middle}.post-views.load-dynamic .post-views-count{color:#0000;transition:color .3s ease-in-out;position:relative}.post-views.load-dynamic .post-views-count:after{opacity:0;transition:opacity .3s ease-in-out;position:relative;color:#6610f2}.post-views.load-dynamic.loaded .post-views-count,.post-views.load-dynamic.load-error .post-views-count{color:inherit}.post-views.load-dynamic.load-error .post-views-count:after{content:none;opacity:0;animation:none}.post-views.load-dynamic.loading .post-views-count,.post-views.load-dynamic.loading .post-views-count:after{box-sizing:border-box}.post-views.load-dynamic.loading.post-views-count:after{content:"";display:block;width:16px;height:16px;border-radius:50%;border:2px solid currentColor;border-color:currentColor transparent currentColor transparent;animation:pvc-loading 1s linear infinite;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);opacity:1}@keyframes pvc-loading{0%{transform:translate(-50%,-50%) rotate(0)}to{transform:translate(-50%,-50%) rotate(360deg)}}1 .pvc-container{display:inline}.pvc-container .pvc-icon,.pvc-custom-format .pvc-icon{display:inline-block;width:16px;height:16px;line-height:1;vertical-align:middle;vertical-align:calc(.5cap - 8px);margin-right:.25em;background-color:currentColor;-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3.5 15v6a1.5 1.5 0 0 0 3 0v-6a1.5 1.5 0 0 0-3 0Zm7-6v12a1.5 1.5 0 0 0 3 0V9a1.5 1.5 0 0 0-3 0Zm7-6v18a1.5 1.5 0 0 0 3 0V3a1.5 1.5 0 0 0-3 0Z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3.5 15v6a1.5 1.5 0 0 0 3 0v-6a1.5 1.5 0 0 0-3 0Zm7-6v12a1.5 1.5 0 0 0 3 0V9a1.5 1.5 0 0 0-3 0Zm7-6v18a1.5 1.5 0 0 0 3 0V3a1.5 1.5 0 0 0-3 0Z'/%3E%3C/svg%3E");-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:100% 100%;mask-size:100% 100%}.pvc-container .pvc-icon-custom,.pvc-custom-format .pvc-icon-custom{vertical-align:middle;background-color:transparent;-webkit-mask-image:none;mask-image:none}.post-views.entry-meta:not(.pvc-container)>span{margin-right:0!important;font:16px/1}.post-views.entry-meta:not(.pvc-container)>span.post-views-icon.dashicons{display:inline-block;font-size:16px;line-height:1;text-decoration:inherit;vertical-align:middle}[data-pvc-metric].load-dynamic>.post-views-count,.post-views.load-dynamic>.post-views-count{color:#0000;transition:color .3s ease-in-out;position:relative}[data-pvc-metric].load-dynamic>.post-views-count:after,.post-views.load-dynamic>.post-views-count:after{opacity:0;transition:opacity .3s ease-in-out;position:relative;color:#6610f2}[data-pvc-metric].load-dynamic.loaded>.post-views-count,[data-pvc-metric].load-dynamic.load-error>.post-views-count,.post-views.load-dynamic.loaded>.post-views-count,.post-views.load-dynamic.load-error>.post-views-count{color:inherit}[data-pvc-metric].load-dynamic.load-error>.post-views-count:after,.post-views.load-dynamic.load-error>.post-views-count:after{content:none;opacity:0;animation:none}[data-pvc-metric].load-dynamic.loading>.post-views-count,[data-pvc-metric].load-dynamic.loading>.post-views-count:after,.post-views.load-dynamic.loading>.post-views-count,.post-views.load-dynamic.loading>.post-views-count:after{box-sizing:border-box}[data-pvc-metric].load-dynamic.loading>.post-views-count:after,.post-views.load-dynamic.loading>.post-views-count:after{content:"";display:block;width:16px;height:16px;border-radius:50%;border:2px solid currentColor;border-color:currentColor transparent currentColor transparent;animation:pvc-loading 1s linear infinite;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);opacity:1}@keyframes pvc-loading{0%{transform:translate(-50%,-50%) rotate(0)}to{transform:translate(-50%,-50%) rotate(360deg)}} -
post-views-counter/tags/1.8.0/includes/class-admin.php
r3647380 r3734102 23 23 24 24 /** 25 * Register Chart.js. 25 * Register Chart.js and the shared metric button component. 26 * 27 * Core owns the metric button runtime so dashboard charts, the column modal, 28 * and extension charts draw the same control. Consumers load the registered 29 * handle when available and keep a local fallback for older Core versions. 26 30 * 27 31 * @return void 28 32 */ 29 33 public function register_chartjs() { 30 wp_register_script( 'pvc-chartjs', POST_VIEWS_COUNTER_URL . '/assets/chartjs/chart.min.js', [ 'jquery' ], '4.5.0', true ); 34 wp_register_script( 'pvc-chartjs', POST_VIEWS_COUNTER_URL . '/assets/chartjs/chart.min.js', [ 'jquery' ], '4.5.1', true ); 35 wp_register_script( 'pvc-metric-toggle', POST_VIEWS_COUNTER_URL . '/js/metric-toggle.js', [], Post_Views_Counter()->defaults['version'], true ); 31 36 } 32 37 … … 47 52 */ 48 53 public function block_editor_rest_api_init() { 49 // get views route54 // update counter totals route 50 55 register_rest_route( 51 56 'post-views-counter', … … 57 62 'args' => [ 58 63 'id' => [ 59 'sanitize_callback' => 'absint', 64 'required' => true, 65 'validate_callback' => [ $this, 'validate_post_id_param' ], 66 'sanitize_callback' => 'absint' 67 ], 68 'views' => [ 69 'validate_callback' => [ $this, 'validate_counter_total_param' ] 70 ], 71 // released alias of views 72 'post_views' => [ 73 'validate_callback' => [ $this, 'validate_counter_total_param' ] 60 74 ] 61 75 ] … … 65 79 66 80 /** 67 * Check whether user has permissions to perform post views update in block editor. 68 * 69 * @param object $request WP_REST_Request 81 * Validate the post ID before absint() can turn a malformed value such 82 * as -20, 20.7 or 20junk into another existing post ID. 83 * 84 * @param mixed $value Submitted value. 85 * @param WP_REST_Request $request Request. 86 * @param string $param Parameter name. 87 * @return true|WP_Error 88 */ 89 public function validate_post_id_param( $value, $request, $param ) { 90 // a positive integer, as an int or a canonical decimal string 91 if ( ( is_int( $value ) || is_string( $value ) ) && filter_var( $value, FILTER_VALIDATE_INT, [ 'options' => [ 'min_range' => 1 ] ] ) !== false && ( is_int( $value ) || ctype_digit( $value ) ) ) 92 return true; 93 94 /* translators: %s: request parameter name */ 95 return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be a positive whole number.', 'post-views-counter' ), $param ), [ 'status' => 400 ] ); 96 } 97 98 /** 99 * Validate one submitted counter total: a whole number, or blank. 100 * 101 * @param mixed $value Submitted value. 102 * @param WP_REST_Request $request Request. 103 * @param string $param Parameter name. 104 * @return true|WP_Error 105 */ 106 public function validate_counter_total_param( $value, $request, $param ) { 107 if ( is_null( $value ) || is_int( $value ) ) 108 return true; 109 110 if ( is_string( $value ) && ( trim( $value ) === '' || preg_match( '/^-?\d+$/', trim( $value ) ) ) ) 111 return true; 112 113 /* translators: %s: request parameter name */ 114 return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be a whole number.', 'post-views-counter' ), $param ), [ 'status' => 400 ] ); 115 } 116 117 /** 118 * Check whether the current user may update this post's counter totals 119 * from the block editor. 120 * 121 * @param WP_REST_Request $request Request. 70 122 * @return bool|WP_Error 71 123 */ 72 124 public function check_rest_route_permissions( $request ) { 73 // break if current user can't edit this post 74 if ( ! current_user_can( 'edit_post', (int) $request->get_param( 'id' ) ) ) 75 return new WP_Error( 'pvc-user-not-allowed', __( 'You are not allowed to edit this item.', 'post-views-counter' ) ); 76 77 // break if views editing is restricted 78 if ( (bool) Post_Views_Counter()->options['display']['restrict_edit_views'] === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) ) 79 return new WP_Error( 'pvc-user-not-allowed', __( 'You are not allowed to edit this item.', 'post-views-counter' ) ); 125 $post_id = (int) $request->get_param( 'id' ); 126 $columns = Post_Views_Counter()->columns; 127 128 // checked first so the route does not reveal which posts exist 129 if ( ! current_user_can( 'edit_post', $post_id ) ) 130 return new WP_Error( 'pvc-user-not-allowed', __( 'You are not allowed to edit this item.', 'post-views-counter' ), [ 'status' => rest_authorization_required_code() ] ); 131 132 if ( ! $columns || ! $columns->is_post_counter_visible_in_editor( $post_id ) ) 133 return new WP_Error( 'pvc-invalid-post', __( 'Invalid post ID.', 'post-views-counter' ), [ 'status' => 404 ] ); 134 135 if ( ! $columns->can_edit_post_counter_in_editor( $post_id ) ) 136 return new WP_Error( 'pvc-user-not-allowed', __( 'You are not allowed to edit this item.', 'post-views-counter' ), [ 'status' => rest_authorization_required_code() ] ); 80 137 81 138 return true; … … 83 140 84 141 /** 85 * REST API callback for block editor endpoint. 86 * 87 * @param array $data 88 * @return string|int 89 */ 90 public function block_editor_update_callback( $data ) { 91 // get main instance 92 $pvc = Post_Views_Counter(); 93 94 // cast post ID 95 $post_id = ! empty( $data['id'] ) ? (int) $data['id'] : 0; 96 97 // cast post views 98 $post_views = ! empty( $data['post_views'] ) ? (int) $data['post_views'] : 0; 99 100 // get countable post types 101 $post_types = (array) $pvc->options['general']['post_types_count']; 102 103 // check if post exists 104 $post = get_post( $post_id ); 105 106 // whether to count this post type or not 107 if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) ) 108 return wp_send_json_error( __( 'Invalid post ID.', 'post-views-counter' ) ); 109 110 // break if current user can't edit this post 111 if ( ! current_user_can( 'edit_post', $post_id ) ) 112 return wp_send_json_error( __( 'You are not allowed to edit this item.', 'post-views-counter' ) ); 113 114 // break if views editing is restricted 115 if ( (bool) $pvc->options['display']['restrict_edit_views'] === true && ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) ) 116 return wp_send_json_error( __( 'You are not allowed to edit this item.', 'post-views-counter' ) ); 117 118 // update post views 119 pvc_update_post_views( $post_id, $post_views ); 120 121 do_action( 'pvc_after_update_post_views_count', $post_id ); 122 123 return $post_id; 142 * REST API callback for the block editor endpoint. 143 * 144 * Only an edited Views total is written. The shared writer re-checks 145 * eligibility. 146 * 147 * @param WP_REST_Request $request Request. 148 * @return WP_REST_Response|WP_Error 149 */ 150 public function block_editor_update_callback( $request ) { 151 $columns = Post_Views_Counter()->columns; 152 153 if ( ! $columns ) 154 return new WP_Error( 'pvc-counter-write-failed', __( 'The counter totals could not be saved.', 'post-views-counter' ), [ 'status' => 500 ] ); 155 156 $views = $request->get_param( 'views' ); 157 158 // released clients send the Views total as post_views 159 if ( is_null( $views ) ) 160 $views = $request->get_param( 'post_views' ); 161 162 // a blank value never means zero 163 if ( is_null( $views ) || trim( (string) $views ) === '' ) 164 return new WP_Error( 'pvc-no-counter-totals', __( 'No counter totals were submitted.', 'post-views-counter' ), [ 'status' => 400 ] ); 165 166 $post_id = (int) $request->get_param( 'id' ); 167 $state = $columns->apply_editor_counter_totals( $post_id, [ 'post_views' => (string) $views ] ); 168 169 if ( is_wp_error( $state ) ) 170 return $state; 171 172 return rest_ensure_response( 173 [ 174 'id' => $post_id, 175 'views' => $state['views'] 176 ] 177 ); 124 178 } 125 179 … … 128 182 * 129 183 * @global string $pagenow 130 * @global string $wp_version131 184 * 132 185 * @return void 133 186 */ 134 187 public function block_editor_enqueue_scripts() { 135 global $pagenow , $wp_version;188 global $pagenow; 136 189 137 190 // get main instance … … 143 196 return; 144 197 198 // enqueue frontend and editor block styles 199 wp_enqueue_style( 'pvc-block-editor', POST_VIEWS_COUNTER_URL . '/css/block-editor.css', '', $pvc->defaults['version'] ); 200 201 $id = (int) get_the_ID(); 202 203 // untracked post types and posts hidden by the display filters get no counter rows 204 if ( ! $id || ! $pvc->columns || ! $pvc->columns->is_post_counter_visible_in_editor( $id ) ) 205 return; 206 207 $state = $pvc->columns->get_post_editor_counter_state( $id ); 208 145 209 // enqueue the bundled block JS file 146 // wp-editor: PluginPostStatusInfo, wp-api-request: wp.apiRequest used on save 147 wp_enqueue_script( 'pvc-block-editor', POST_VIEWS_COUNTER_URL . '/js/block-editor.js', [ 'wp-element', 'wp-components', 'wp-editor', 'wp-data', 'wp-plugins', 'wp-api-request' ], $pvc->defaults['version'], false ); 148 149 // restrict editing 150 $can_edit = false; 151 152 $restrict = (bool) $pvc->options['display']['restrict_edit_views']; 153 154 if ( $restrict === false || ( $restrict === true && current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ) ) ) 155 $can_edit = true; 156 157 // get total post views 158 $id = get_the_ID(); 159 $count = pvc_get_post_views( $id ); 160 161 // disable views display and editing? 162 if ( apply_filters( 'pvc_admin_display_views', true, $id ) === false ) { 163 $count = '—'; 164 $can_edit = false; 165 } 210 // wp-edit-post: PluginPostStatusInfo, wp-api-fetch: counter totals request after save 211 wp_enqueue_script( 'pvc-block-editor', POST_VIEWS_COUNTER_URL . '/js/block-editor.js', [ 'wp-element', 'wp-components', 'wp-editor', 'wp-edit-post', 'wp-data', 'wp-plugins', 'wp-api-fetch' ], $pvc->defaults['version'], false ); 166 212 167 213 // prepare script data 168 214 $script_data = [ 169 'postID' => $id, 170 'postViews' => $count, 171 'canEdit' => $can_edit, 172 'nonce' => wp_create_nonce( 'wp_rest' ), 173 'wpGreater53' => version_compare( $wp_version, '5.3', '>=' ), 174 'textPostViews' => esc_html__( 'Post Views', 'post-views-counter' ), 175 'textHelp' => esc_html__( 'Adjust the views count for this post.', 'post-views-counter' ), 176 'textCancel' => esc_html__( 'Cancel', 'post-views-counter' ) 215 'postID' => $id, 216 'views' => $state['views'], 217 'canEdit' => $state['editable'], 218 'locale' => str_replace( '_', '-', get_user_locale() ), 219 'i18n' => [ 220 'views' => __( 'Views', 'post-views-counter' ), 221 /* translators: 1: metric name, 2: formatted count */ 222 'valueLabel' => __( '%1$s: %2$s.', 'post-views-counter' ), 223 'help' => __( 'Lifetime totals. Changing them does not alter daily, weekly, monthly, or yearly history.', 'post-views-counter' ), 224 'cancel' => __( 'Cancel', 'post-views-counter' ), 225 'saveFailed' => __( 'Views could not be saved.', 'post-views-counter' ) 226 ] 177 227 ]; 178 228 179 229 wp_add_inline_script( 'pvc-block-editor', 'var pvcEditorArgs = ' . wp_json_encode( $script_data ) . ";\n", 'before' ); 180 181 // enqueue frontend and editor block styles182 wp_enqueue_style( 'pvc-block-editor', POST_VIEWS_COUNTER_URL . '/css/block-editor.css', '', $pvc->defaults['version'] );183 230 } 184 231 } -
post-views-counter/tags/1.8.0/includes/class-columns-modal.php
r3537950 r3734102 63 63 wp_register_script( 'pvc-column-modal', POST_VIEWS_COUNTER_URL . '/js/admin-columns.js', [ 'jquery', 'pvc-chartjs', 'pvc-micromodal' ], $pvc->defaults['version'], true ); 64 64 65 // localize script 66 wp_add_inline_script( 'pvc-admin-columns', 'var pvcColumnModal = ' . wp_json_encode( [ 67 'ajaxURL' => admin_url( 'admin-ajax.php' ), 68 'nonce' => wp_create_nonce( 'pvc-column-modal' ), 69 'i18n' => [ 70 'loading' => __( 'Loading...', 'post-views-counter' ), 71 'close' => __( 'Close', 'post-views-counter' ), 72 'error' => __( 'An error occurred while loading data.', 'post-views-counter' ), 73 'summary' => __( 'Total views in this period:', 'post-views-counter' ), 74 'view' => __( 'view', 'post-views-counter' ), 75 'views' => __( 'views', 'post-views-counter' ) 65 $extension_owns_modal = $this->extension_modal_owner_is_loaded(); 66 $current_extension_owner = $extension_owns_modal && $this->extension_modal_owner_replaces_base_later(); 67 68 // The configuration is created once by the base plugin. A compatible modal 69 // owner transfers this script data to its controller. Legacy extensions supply 70 // their own declaration, so the base must not add a second assignment. 71 if ( ! $extension_owns_modal || $current_extension_owner ) 72 wp_add_inline_script( 'pvc-admin-columns', 'var pvcColumnModal = ' . wp_json_encode( $this->get_modal_config( $extension_owns_modal ) ) . "\n", 'before' ); 73 74 // A loaded extension modal owner renders its own compatible footer markup. 75 // Do not rely on a released extension removing this callback after registration. 76 if ( ! $extension_owns_modal ) 77 add_action( 'admin_footer', [ $this, 'render_modal_html' ] ); 78 } 79 80 /** 81 * Build the private configuration shared by the base and extension modal 82 * controllers. 83 * 84 * @param bool $extension_owns_modal Whether a compatible extension footer 85 * owner is loaded. 86 * @return array 87 */ 88 private function get_modal_config( $extension_owns_modal ) { 89 return [ 90 'ajaxURL' => admin_url( 'admin-ajax.php' ), 91 'nonce' => wp_create_nonce( 'pvc-column-modal' ), 92 'handlerNamespace' => 'pvcCoreModal', 93 'modalOwner' => $extension_owns_modal ? 'pro' : 'core', 94 'i18n' => [ 95 'loading' => __( 'Loading...', 'post-views-counter' ), 96 'close' => __( 'Close', 'post-views-counter' ), 97 'error' => __( 'An error occurred while loading data.', 'post-views-counter' ), 98 'summary' => __( 'Views in this period:', 'post-views-counter' ), 99 'retry' => __( 'Retry', 'post-views-counter' ), 100 'view' => __( 'view', 'post-views-counter' ), 101 'views' => __( 'views', 'post-views-counter' ) 76 102 ] 77 ] ) . "\n", 'before' ); 78 79 // add modal HTML to footer 80 add_action( 'admin_footer', [ $this, 'render_modal_html' ] ); 103 ]; 104 } 105 106 /** 107 * Check whether an instantiated extension modal renderer owns this request. 108 * 109 * Class presence alone is insufficient: partial extension bootstraps must leave 110 * the base modal active until an actual renderer callback is registered. 111 * 112 * @return bool 113 */ 114 private function extension_modal_owner_is_loaded() { 115 global $wp_filter; 116 117 if ( ! class_exists( 'Post_Views_Counter_Pro_Columns_Modal' ) || ! isset( $wp_filter['admin_footer'] ) ) 118 return false; 119 120 foreach ( $wp_filter['admin_footer']->callbacks as $callbacks ) { 121 foreach ( $callbacks as $callback ) { 122 if ( ! is_array( $callback['function'] ) || ! isset( $callback['function'][0], $callback['function'][1] ) ) 123 continue; 124 125 if ( $callback['function'][1] === 'render_modal_html' && is_a( $callback['function'][0], 'Post_Views_Counter_Pro_Columns_Modal' ) ) 126 return true; 127 } 128 } 129 130 return false; 131 } 132 133 /** 134 * Check whether the loaded extension owner transfers base script data at 135 * priority 30. 136 * 137 * @return bool 138 */ 139 private function extension_modal_owner_replaces_base_later() { 140 global $wp_filter; 141 142 if ( ! isset( $wp_filter['admin_enqueue_scripts']->callbacks[30] ) ) 143 return false; 144 145 foreach ( $wp_filter['admin_enqueue_scripts']->callbacks[30] as $callback ) { 146 if ( is_array( $callback['function'] ) && isset( $callback['function'][0], $callback['function'][1] ) && $callback['function'][1] === 'remove_base_modal' && is_a( $callback['function'][0], 'Post_Views_Counter_Pro_Columns_Modal' ) ) 147 return true; 148 } 149 150 return false; 81 151 } 82 152 … … 115 185 wp_send_json_error( [ 'message' => __( 'Post type is not tracked.', 'post-views-counter' ) ] ); 116 186 187 // the same rule as the chart link in the list column 188 if ( ! $pvc->columns || ! $pvc->columns->current_user_can_view_post_chart( $post ) ) 189 wp_send_json_error( [ 'message' => __( 'Access denied for this post.', 'post-views-counter' ) ] ); 190 117 191 // check display permission for this specific post 118 192 if ( apply_filters( 'pvc_admin_display_post_views', true, $post_id ) === false ) … … 120 194 121 195 // get period (format: YYYYMM or empty for current month) 122 $period_str = isset( $_POST['period'] ) && ! empty( $_POST['period'] ) ? preg_replace( '/[^0-9]/', '', $_POST['period'] ) : ''; 196 if ( isset( $_POST['period'] ) && ! is_scalar( $_POST['period'] ) ) 197 wp_send_json_error( [ 'message' => __( 'Invalid period.', 'post-views-counter' ) ] ); 198 199 $period_str = isset( $_POST['period'] ) && ! empty( $_POST['period'] ) ? preg_replace( '/[^0-9]/', '', wp_unslash( (string) $_POST['period'] ) ) : ''; 123 200 124 201 // parse period or use current 125 if ( $period_str && strlen( $period_str ) === 6 ) { 126 $year = substr( $period_str, 0, 4 ); 127 $month = substr( $period_str, 4, 2 ); 128 $date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() ); 129 130 if ( ! $date ) 131 $date = new DateTime( 'now', wp_timezone() ); 132 } else { 133 $date = new DateTime( 'now', wp_timezone() ); 134 } 202 $date = $this->get_requested_month( $period_str, $this->get_counting_now() ); 135 203 136 204 $year = $date->format( 'Y' ); … … 138 206 $last_day = $date->format( 't' ); 139 207 140 // fetch views data 208 wp_send_json_success( $this->get_paired_column_chart_data( $post, (int) $year, (int) $month, (int) $last_day ) ); 209 } 210 211 /** 212 * Build the Views modal response with the shared metric dataset style. 213 * 214 * The released total_views and period_has_data keys are kept for any 215 * consumer of the legacy payload. 216 * 217 * @param WP_Post $post Post object. 218 * @param int $year Requested year. 219 * @param int $month Requested month. 220 * @param int $last_day Days in the requested month. 221 * @return array 222 */ 223 private function get_paired_column_chart_data( $post, $year, $month, $last_day ) { 224 $pvc = Post_Views_Counter(); 141 225 $views = pvc_get_views( [ 142 'post_id' => $post_id, 143 'post_type' => $post->post_type, 144 'fields' => 'date=>views', 145 'views_query' => [ 146 'year' => (int) $year, 147 'month' => (int) $month 148 ] 226 'post_id' => $post->ID, 227 'post_type' => $post->post_type, 228 'fields' => 'date=>views', 229 'views_query' => [ 'year' => $year, 'month' => $month ] 149 230 ] ); 150 151 // get colors152 $colors = $pvc->functions->get_colors();153 154 // prepare response data155 231 $data = [ 156 'post_id' => $post_id, 157 'post_title'=> get_the_title( $post_id ), 158 'period' => $year . $month, 159 'design' => [ 160 'fill' => true, 161 'backgroundColor' => 'rgba(' . $colors['r'] . ',' . $colors['g'] . ',' . $colors['b'] . ', 0.2)', 162 'borderColor' => 'rgba(' . $colors['r'] . ',' . $colors['g'] . ',' . $colors['b'] . ', 1)', 163 'borderWidth' => 1.2, 164 'borderDash' => [], 165 'pointBorderColor' => 'rgba(' . $colors['r'] . ',' . $colors['g'] . ',' . $colors['b'] . ', 1)', 166 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)', 167 'pointBorderWidth' => 1.2 232 'post_id' => (int) $post->ID, 233 'post_title' => get_the_title( $post->ID ), 234 'period' => sprintf( '%04d%02d', $year, $month ), 235 'dates_html' => $this->generate_modal_dates( $year, $month ), 236 'data' => [ 237 'labels' => [], 238 'dates' => [], 239 'datasets' => [ 240 array_merge( [ 241 'metric' => 'views', 242 'label' => __( 'Views', 'post-views-counter' ), 243 'data' => [] 244 ], $pvc->functions->get_metric_dataset_style( 'views', 'line', [ 'fill' => true ] ) ) 245 ] 168 246 ], 169 'data' => [ 170 'labels' => [], 171 'dates' => [], 172 'datasets' => [ 173 [ 174 'label' => get_the_title( $post_id ), 175 'data' => [] 176 ] 177 ] 178 ] 247 'totals' => [ 'views' => 0 ] 179 248 ]; 180 249 181 // generate dates and data 182 for ( $i = 1; $i <= $last_day; $i++ ) { 183 $date_key = $year . $month . str_pad( $i, 2, '0', STR_PAD_LEFT ); 184 185 // labels: show only odd days 186 $data['data']['labels'][] = ( $i % 2 === 0 ? '' : $i ); 187 188 // formatted dates for tooltips 189 $data['data']['dates'][] = date_i18n( get_option( 'date_format' ), strtotime( $year . '-' . $month . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) ) ); 190 191 // view count 250 $timezone = wp_timezone(); 251 252 for ( $day = 1; $day <= $last_day; $day++ ) { 253 $date_key = sprintf( '%04d%02d%02d', $year, $month, $day ); 254 $timestamp = ( new DateTimeImmutable( sprintf( '%04d-%02d-%02d 00:00:00', $year, $month, $day ), $timezone ) )->getTimestamp(); 255 256 $data['data']['labels'][] = $day % 2 === 0 ? '' : $day; 257 $data['data']['dates'][] = wp_date( get_option( 'date_format' ), $timestamp, $timezone ); 192 258 $data['data']['datasets'][0]['data'][] = isset( $views[$date_key] ) ? (int) $views[$date_key] : 0; 193 259 } 194 260 195 // calculate total views for the period 196 $data['total_views'] = array_sum( $data['data']['datasets'][0]['data'] ); 197 198 // check if there is any period-specific data 199 $period_has_data = false; 200 foreach ( $data['data']['datasets'][0]['data'] as $val ) { 201 if ( (int) $val > 0 ) { 202 $period_has_data = true; 203 break; 204 } 205 } 206 207 $data['period_has_data'] = $period_has_data; 208 209 // generate date navigation HTML 210 $data['dates_html'] = $this->generate_modal_dates( (int) $year, (int) $month ); 211 212 wp_send_json_success( $data ); 261 $data['totals']['views'] = array_sum( $data['data']['datasets'][0]['data'] ); 262 $data['total_views'] = $data['totals']['views']; 263 $data['period_has_data'] = $data['totals']['views'] > 0; 264 $data['data'] = Post_Views_Counter()->functions->format_chart_datasets( $data['data'] ); 265 266 return $data; 213 267 } 214 268 … … 220 274 * @return string 221 275 */ 222 private function generate_modal_dates( $year, $month ) { 223 // previous month 224 $prev_date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() ); 225 $prev_date->modify( '-1 month' ); 226 227 // next month 228 $next_date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() ); 229 $next_date->modify( '+1 month' ); 230 231 // current 232 $current_date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() ); 233 234 // check if next is in the future 235 $now = new DateTime( 'now', wp_timezone() ); 236 $can_go_next = $next_date <= $now; 237 276 private function generate_modal_dates( $year, $month, $now = null ) { 277 $timezone = wp_timezone(); 278 279 if ( ! ( $now instanceof DateTimeInterface ) ) 280 $now = $this->get_counting_now(); 281 282 $current_date = $this->parse_month( sprintf( '%04d-%02d', $year, $month ) ); 283 284 if ( ! $current_date ) 285 $current_date = $this->parse_month( $now->format( 'Y-m' ) ); 286 287 $prev_date = $current_date->modify( '-1 month' ); 288 $next_date = $current_date->modify( '+1 month' ); 289 290 // next is available once its month has started in the counting clock 291 $can_go_next = (int) $next_date->format( 'Ym' ) <= (int) $now->format( 'Ym' ); 292 238 293 $html = '<div class="pvc-modal-nav">'; 239 $html .= '<a href="#" class="pvc-modal-nav-prev" data-period="' . $prev_date->format( 'Ym' ) . '">‹ ' . date_i18n( 'F Y', $prev_date->getTimestamp()) . '</a>';240 $html .= '<span class="pvc-modal-nav-current">' . date_i18n( 'F Y', $current_date->getTimestamp()) . '</span>';294 $html .= '<a href="#" class="pvc-modal-nav-prev" data-period="' . $prev_date->format( 'Ym' ) . '">‹ ' . wp_date( 'F Y', $prev_date->getTimestamp(), $timezone ) . '</a>'; 295 $html .= '<span class="pvc-modal-nav-current">' . wp_date( 'F Y', $current_date->getTimestamp(), $timezone ) . '</span>'; 241 296 242 297 if ( $can_go_next ) 243 $html .= '<a href="#" class="pvc-modal-nav-next" data-period="' . $next_date->format( 'Ym' ) . '">' . date_i18n( 'F Y', $next_date->getTimestamp()) . ' ›</a>';298 $html .= '<a href="#" class="pvc-modal-nav-next" data-period="' . $next_date->format( 'Ym' ) . '">' . wp_date( 'F Y', $next_date->getTimestamp(), $timezone ) . ' ›</a>'; 244 299 else 245 $html .= '<span class="pvc-modal-nav-next pvc-disabled">' . date_i18n( 'F Y', $next_date->getTimestamp()) . ' ›</span>';300 $html .= '<span class="pvc-modal-nav-next pvc-disabled">' . wp_date( 'F Y', $next_date->getTimestamp(), $timezone ) . ' ›</span>'; 246 301 247 302 $html .= '</div>'; 248 303 249 304 return $html; 305 } 306 307 /** 308 * Get the current time in the clock that buckets the stored periods. 309 * 310 * @return DateTimeImmutable 311 */ 312 private function get_counting_now() { 313 return new DateTimeImmutable( 'now', Post_Views_Counter_Visits_Query::get_timezone() ); 314 } 315 316 /** 317 * Get the first day of the requested month, or of the current month in the 318 * counting clock when none (or an invalid one) is requested. 319 * 320 * @param string $period_str Requested period in YYYYMM format, or empty. 321 * @param DateTimeInterface $now Current time in the counting clock. 322 * @return DateTimeImmutable 323 */ 324 private function get_requested_month( $period_str, $now ) { 325 $date = false; 326 327 if ( $period_str && strlen( $period_str ) === 6 ) 328 $date = $this->parse_month( substr( $period_str, 0, 4 ) . '-' . substr( $period_str, 4, 2 ) ); 329 330 return $date ? $date : $this->parse_month( $now->format( 'Y-m' ) ); 331 } 332 333 /** 334 * Parse one exact calendar month without inheriting the current day. 335 * 336 * @param string $value Month in Y-m format. 337 * @return DateTimeImmutable|false 338 */ 339 private function parse_month( $value ) { 340 $date = DateTimeImmutable::createFromFormat( '!Y-m', $value, wp_timezone() ); 341 $errors = DateTimeImmutable::getLastErrors(); 342 343 if ( ! $date || ( is_array( $errors ) && ( ! empty( $errors['warning_count'] ) || ! empty( $errors['error_count'] ) ) ) || $date->format( 'Y-m' ) !== $value ) 344 return false; 345 346 return $date; 250 347 } 251 348 … … 267 364 <div class="pvc-modal-content-top"> 268 365 <div class="pvc-modal-summary"> 269 <span class="pvc-modal-views-label">< /span>366 <span class="pvc-modal-views-label"><?php esc_html_e( 'Views in this period:', 'post-views-counter' ); ?></span> 270 367 <span class="pvc-modal-views-data"> 271 <span class="pvc-modal-count "></span>368 <span class="pvc-modal-count pvc-modal-count-views"></span> 272 369 </span> 273 370 </div> 274 <div class="pvc-modal-tabs" role="tablist">275 <button type="button" class="pvc-modal-tab pvc-pro" disabled ><span><?php _e( 'Year', 'post-views-counter' ); ?></span></button>276 <button type="button" class="pvc-modal-tab active" ><span><?php _e( 'Month', 'post-views-counter' ); ?></span></button>277 <button type="button" class="pvc-modal-tab pvc-pro" disabled ><span><?php _e( 'Week', 'post-views-counter' ); ?></span></button>371 <div class="pvc-modal-tabs" role="group" aria-label="<?php esc_attr_e( 'Chart period', 'post-views-counter' ); ?>"> 372 <button type="button" class="pvc-modal-tab pvc-pro" disabled aria-pressed="false"><span><?php _e( 'Year', 'post-views-counter' ); ?></span></button> 373 <button type="button" class="pvc-modal-tab active" aria-pressed="true"><span><?php _e( 'Month', 'post-views-counter' ); ?></span></button> 374 <button type="button" class="pvc-modal-tab pvc-pro" disabled aria-pressed="false"><span><?php _e( 'Week', 'post-views-counter' ); ?></span></button> 278 375 </div> 279 376 </div> 280 <div class="pvc-modal-chart-container"> 281 <canvas id="pvc-modal-chart" height="200"></canvas> 282 <span class="spinner"></span> 283 </div> 377 <div id="pvc-modal-chart-panel" class="pvc-modal-chart-container"> 378 <canvas id="pvc-modal-chart" height="200"></canvas> 379 <span class="spinner"></span> 380 </div> 381 <div class="pvc-modal-status" role="status" aria-live="polite"></div> 284 382 <div class="pvc-modal-content-middle" style="display: none;"> 285 383 <div class="pvc-modal-insights"> -
post-views-counter/tags/1.8.0/includes/class-columns.php
r3578455 r3734102 10 10 */ 11 11 class Post_Views_Counter_Columns { 12 13 private $bulk_counter_result = null; 12 14 13 15 /** … … 25 27 add_action( 'bulk_edit_custom_box', [ $this, 'quick_edit_custom_box' ], 10, 2 ); 26 28 add_action( 'quick_edit_custom_box', [ $this, 'quick_edit_custom_box' ], 10, 2 ); 29 // Retained for compatibility with any external consumer. The shipped UI 30 // no longer calls it; native Bulk Edit owns current counter writes. 27 31 add_action( 'wp_ajax_save_bulk_post_views', [ $this, 'save_bulk_post_views' ] ); 28 } 29 30 /** 31 * Sanitize manual post views input. 32 add_action( 'bulk_edit_posts', [ $this, 'bulk_edit_post_counters' ], 10, 2 ); 33 add_action( 'admin_notices', [ $this, 'bulk_counter_admin_notice' ] ); 34 add_filter( 'removable_query_args', [ $this, 'add_removable_query_args' ] ); 35 add_action( 'pre_get_posts', [ $this, 'prepare_admin_list_sort' ], 0 ); 36 } 37 38 /** 39 * Sanitize one absolute counter total. 32 40 * 33 41 * @param mixed $value 34 42 * @return int|null 35 43 */ 36 private function sanitize_ post_views_input( $value ) {44 private function sanitize_counter_total_input( $value ) { 37 45 if ( ! is_scalar( $value ) ) 38 46 return null; … … 40 48 $value = trim( wp_unslash( (string) $value ) ); 41 49 42 if ( $value === '' || ! is_numeric($value ) )50 if ( $value === '' || ! preg_match( '/^-?\d+$/', $value ) ) 43 51 return null; 44 52 … … 46 54 47 55 return $count < 0 ? 0 : $count; 56 } 57 58 /** 59 * Collect the nonblank Views total submitted by an editor. 60 * 61 * @param array|null $source Submitted fields. Defaults to the POST body. 62 * @return array|null Null indicates malformed input. 63 */ 64 private function get_submitted_counter_totals( $source = null ) { 65 if ( is_null( $source ) ) 66 $source = $_POST; 67 68 if ( ! is_array( $source ) ) 69 return null; 70 71 if ( ! array_key_exists( 'post_views', $source ) ) 72 return []; 73 74 if ( ! is_scalar( $source['post_views'] ) ) 75 return null; 76 77 if ( trim( wp_unslash( (string) $source['post_views'] ) ) === '' ) 78 return []; 79 80 $value = $this->sanitize_counter_total_input( $source['post_views'] ); 81 82 if ( is_null( $value ) ) 83 return null; 84 85 // A value equal to the one the form was loaded with was not edited. 86 // Writing it back would roll back Views counted since then. 87 if ( array_key_exists( 'current_post_views', $source ) && $this->sanitize_counter_total_input( $source['current_post_views'] ) === $value ) 88 return []; 89 90 return [ 'views' => $value ]; 91 } 92 93 /** 94 * Check whether a post's counter totals appear on its edit screen. 95 * 96 * The edit screen is a separate feature from the list column, so the 97 * column toggle does not apply here. 98 * 99 * @internal Shared by the Classic Editor and the block editor. 100 * 101 * @param int $post_id Post ID. 102 * @return bool 103 */ 104 public function is_post_counter_visible_in_editor( $post_id ) { 105 $post = get_post( (int) $post_id ); 106 107 if ( ! $post ) 108 return false; 109 110 return in_array( $post->post_type, (array) Post_Views_Counter()->options['general']['post_types_count'], true ) 111 && apply_filters( 'pvc_admin_display_post_views', true, $post->ID ) !== false 112 // The block editor has always honoured this filter name. 113 && apply_filters( 'pvc_admin_display_views', true, $post->ID ) !== false; 114 } 115 116 /** 117 * Check whether the current user may edit a post's counter totals on its 118 * edit screen. 119 * 120 * @internal Shared by the Classic Editor and the block editor. 121 * 122 * @param int $post_id Post ID. 123 * @return bool 124 */ 125 public function can_edit_post_counter_in_editor( $post_id ) { 126 $pvc = Post_Views_Counter(); 127 128 return $this->is_post_counter_visible_in_editor( $post_id ) 129 && current_user_can( 'edit_post', (int) $post_id ) 130 && ! empty( $pvc->options['display']['restrict_edit_views'] ) 131 && current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ); 132 } 133 134 /** 135 * Get the lifetime Views total shown on a post's edit screen. 136 * 137 * @internal Shared by the Classic Editor and the block editor. 138 * 139 * @param int $post_id Post ID. 140 * @return array 141 */ 142 public function get_post_editor_counter_state( $post_id ) { 143 $post_id = (int) $post_id; 144 145 return [ 146 'views' => (int) pvc_get_post_views( $post_id ), 147 'editable' => $this->can_edit_post_counter_in_editor( $post_id ) 148 ]; 149 } 150 151 /** 152 * Apply counter totals submitted by the block editor. 153 * 154 * @internal Used only by the block editor REST route. 155 * 156 * @param int $post_id Post ID. 157 * @param array $source Submitted fields keyed post_views. 158 * @return array|WP_Error Committed totals, the reason nothing was written, or 159 * pvc-counter-read-failed when the committed total 160 * cannot be read back. 161 */ 162 public function apply_editor_counter_totals( $post_id, $source ) { 163 $post_id = (int) $post_id; 164 165 if ( ! $this->is_post_counter_visible_in_editor( $post_id ) ) 166 return new WP_Error( 'pvc-invalid-post', __( 'Invalid post ID.', 'post-views-counter' ), [ 'status' => 404 ] ); 167 168 if ( ! $this->can_edit_post_counter_in_editor( $post_id ) ) 169 return new WP_Error( 'pvc-user-not-allowed', __( 'You are not allowed to edit this item.', 'post-views-counter' ), [ 'status' => rest_authorization_required_code() ] ); 170 171 $updates = $this->get_submitted_counter_totals( $source ); 172 173 if ( is_null( $updates ) ) 174 return new WP_Error( 'pvc-invalid-counter-totals', __( 'Invalid counter totals.', 'post-views-counter' ), [ 'status' => 400 ] ); 175 176 if ( ! $this->update_post_counter_totals( $post_id, $updates ) ) 177 return new WP_Error( 'pvc-counter-write-failed', __( 'The counter totals could not be saved.', 'post-views-counter' ), [ 'status' => 500 ] ); 178 179 $state = $this->get_post_editor_counter_state( $post_id ); 180 181 // pvc_get_post_views() may still hold the total it cached before the write 182 $views = $this->get_stored_post_views_total( $post_id ); 183 184 if ( $views === null ) 185 return new WP_Error( 'pvc-counter-read-failed', __( 'The saved counter totals could not be read back.', 'post-views-counter' ), [ 'status' => 500 ] ); 186 187 $state['views'] = $views; 188 189 return $state; 190 } 191 192 /** 193 * Read one post's committed lifetime Views total, bypassing read caches. 194 * 195 * @param int $post_id Post ID. 196 * @return int|null The total (0 when no row exists), or null when the read failed. 197 */ 198 private function get_stored_post_views_total( $post_id ) { 199 global $wpdb; 200 201 $where = ' WHERE `id` = %d AND `type` = %d AND `period` = %s'; 202 $args = [ (int) $post_id, 4, 'total' ]; 203 204 if ( pvc_post_views_has_content_column() ) { 205 $where .= ' AND `content` = %d'; 206 $args[] = 0; 207 } 208 209 $wpdb->last_error = ''; 210 $count = $wpdb->get_var( $wpdb->prepare( 'SELECT `count` FROM `' . $wpdb->prefix . 'post_views`' . $where, $args ) ); 211 212 // a failed read must never pass for a stored zero 213 return $wpdb->last_error === '' ? (int) $count : null; 214 } 215 216 /** 217 * Check whether the current request is one exact WordPress AJAX action. 218 * 219 * @param string $action AJAX action. 220 * @return bool 221 */ 222 private function is_ajax_action( $action ) { 223 $is_ajax = function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : defined( 'DOING_AJAX' ) && DOING_AJAX; 224 225 return $is_ajax 226 && isset( $_REQUEST['action'] ) 227 && is_scalar( $_REQUEST['action'] ) 228 && sanitize_key( wp_unslash( (string) $_REQUEST['action'] ) ) === $action; 229 } 230 231 /** 232 * Check whether WordPress is saving one Quick Edit row. 233 * 234 * @return bool 235 */ 236 private function is_quick_edit_request() { 237 return $this->is_ajax_action( 'inline-save' ) && isset( $_POST['_inline_edit'] ); 238 } 239 240 /** 241 * Check whether the request submitted this post's edit form. The Classic 242 * Editor, the attachment editor and Quick Edit all send the edited post as 243 * post_ID. 244 * 245 * @param int $post_id Post ID being saved. 246 * @return bool 247 */ 248 private function is_submitted_post( $post_id ) { 249 if ( ! isset( $_POST['post_ID'] ) || ! is_scalar( $_POST['post_ID'] ) ) 250 return false; 251 252 $submitted = trim( wp_unslash( (string) $_POST['post_ID'] ) ); 253 254 return preg_match( '/^[1-9]\d*$/', $submitted ) === 1 && (int) $submitted === (int) $post_id; 255 } 256 257 /** 258 * Check whether the ordinary save_post callback is running inside native 259 * WordPress Bulk Edit. The bulk_edit_posts completion hook owns current 260 * native Bulk Edit counter writes there. 261 * 262 * @return bool 263 */ 264 private function is_native_bulk_edit_request() { 265 return isset( $_REQUEST['bulk_edit'] ); 266 } 267 268 /** 269 * Check all server-side conditions for one post total adjustment. 270 * 271 * @param int $post_id Post ID. 272 * @return bool 273 */ 274 private function can_update_post_counter_totals( $post_id ) { 275 $pvc = Post_Views_Counter(); 276 $post = get_post( $post_id ); 277 278 return $post 279 && ! empty( $pvc->options['display']['post_views_column'] ) 280 && in_array( $post->post_type, (array) $pvc->options['general']['post_types_count'], true ) 281 && apply_filters( 'pvc_admin_display_post_views', true, $post_id ) !== false 282 && current_user_can( 'edit_post', $post_id ) 283 && ! empty( $pvc->options['display']['restrict_edit_views'] ) 284 && current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ); 285 } 286 287 /** 288 * Retire the cached lifetime Views total of one post after a manual write. 289 * 290 * pvc_get_post_views() and shared cache priming use the query's MD5 key, so 291 * only the single-post total query needs to be rebuilt. The content condition 292 * is included when the shared table has a content dimension. 293 * 294 * @param int $post_id Post ID. 295 * @return void 296 */ 297 private function retire_post_views_cache( $post_id ) { 298 global $wpdb; 299 300 $query = "SELECT SUM(count) AS views FROM " . $wpdb->prefix . "post_views WHERE id IN (%d) AND type = %d AND period = %s"; 301 302 wp_cache_delete( md5( $wpdb->prepare( $query, (int) $post_id, 4, 'total' ) ), 'pvc-get_post_views' ); 303 wp_cache_delete( md5( $wpdb->prepare( $query . ' AND content = %d', (int) $post_id, 4, 'total', 0 ) ), 'pvc-get_post_views' ); 304 } 305 306 /** 307 * Write one post's lifetime Views total without altering historical buckets. 308 * 309 * @param int $post_id Post ID. 310 * @param array $updates Absolute totals; only views is written. 311 * @return bool 312 */ 313 private function update_post_counter_totals( $post_id, $updates ) { 314 if ( ! isset( $updates['views'] ) ) 315 return true; 316 317 // Compare with the committed total, never a cached read: a stale cached 318 // total equal to the submitted value would skip a real edit. 319 $current = $this->get_stored_post_views_total( $post_id ); 320 321 if ( $current === null ) 322 return false; 323 324 // The submitted Views value is already a validated, normalized 325 // non-negative integer. Pass it directly so pvc_update_post_views() 326 // remains the single owner of the pvc_update_post_views_count filter 327 // on this path. 328 $views = (int) $updates['views']; 329 330 if ( $current === $views ) 331 return true; 332 333 global $wpdb; 334 $wpdb->last_error = ''; 335 336 if ( pvc_update_post_views( $post_id, $views ) === false || $wpdb->last_error !== '' ) 337 return false; 338 339 $this->retire_post_views_cache( $post_id ); 340 do_action( 'pvc_after_update_post_views_count', $post_id ); 341 342 return true; 48 343 } 49 344 … … 58 353 global $post; 59 354 60 // get main instance 61 $pvc = Post_Views_Counter(); 62 $post_types = (array) $pvc->options['general']['post_types_count']; 63 64 // break if display is not allowed 65 if ( ! $pvc->options['display']['post_views_column'] || ! in_array( $post->post_type, $post_types, true ) ) 66 return; 67 68 // check if user can see post stats 69 if ( apply_filters( 'pvc_admin_display_post_views', true, $post->ID ) === false ) 70 return; 71 72 // get total post views 73 $count = (int) pvc_get_post_views( $post->ID ); ?> 355 if ( ! $post || ! $this->is_post_counter_visible_in_editor( $post->ID ) ) 356 return; 357 358 $state = $this->get_post_editor_counter_state( $post->ID ); ?> 74 359 75 360 <div class="misc-pub-section" id="post-views"> 76 361 77 <?php wp_nonce_field( 'post_views_count', 'pvc_nonce' ); ?> 78 79 <span id="post-views-display"> 80 <?php echo __( 'Post Views', 'post-views-counter' ) . ': <b>' . number_format_i18n( $count ) . '</b>'; ?> 362 <span id="post-views-display" class="pvc-editor-counter-line"> 363 <?php echo esc_html__( 'Views', 'post-views-counter' ) . ': <b>' . esc_html( number_format_i18n( $state['views'] ) ) . '</b>'; ?> 81 364 </span> 82 365 83 366 <?php 84 // allow editing 85 $allow_edit = (bool) $pvc->options['display']['restrict_edit_views']; 86 87 // allow editing condition 88 $allow_edit_condition = (bool) current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ); 89 90 if ( $allow_edit === true && $allow_edit_condition === true ) { 367 if ( $state['editable'] ) { 368 wp_nonce_field( 'post_views_count', 'pvc_nonce' ); 91 369 ?> 92 <a href="#post-views" class="edit-post-views hide-if-no-js" ><?php _e( 'Edit', 'post-views-counter' ); ?></a>370 <a href="#post-views" class="edit-post-views hide-if-no-js" role="button"><?php esc_html_e( 'Edit', 'post-views-counter' ); ?><span class="screen-reader-text"> <?php esc_html_e( 'Views', 'post-views-counter' ); ?></span></a> 93 371 94 372 <div id="post-views-input-container" class="hide-if-js"> 95 373 96 <p><?php _e( 'Adjust the views count for this post.', 'post-views-counter' ); ?></p> 97 <input type="hidden" name="current_post_views" id="post-views-current" value="<?php echo esc_attr( $count ); ?>" /> 98 <input type="text" name="post_views" id="post-views-input" value="<?php echo esc_attr( $count ); ?>"/><br /> 374 <p class="pvc-editor-counter-field"> 375 <label for="post-views-input"><?php esc_html_e( 'Views', 'post-views-counter' ); ?></label> 376 <input type="hidden" name="current_post_views" id="post-views-current" value="<?php echo esc_attr( $state['views'] ); ?>" /> 377 <input type="number" min="0" step="1" inputmode="numeric" name="post_views" id="post-views-input" value="<?php echo esc_attr( $state['views'] ); ?>" /> 378 </p> 379 380 <p class="description"><?php esc_html_e( 'Lifetime totals. Changing them does not alter daily, weekly, monthly, or yearly history.', 'post-views-counter' ); ?></p> 381 99 382 <p> 100 <a href="#post-views" class="save-post-views hide-if-no-js button"><?php _e( 'OK', 'post-views-counter' ); ?></a>101 <a href="#post-views" class="cancel-post-views hide-if-no-js "><?php_e( 'Cancel', 'post-views-counter' ); ?></a>383 <a href="#post-views" class="save-post-views hide-if-no-js button"><?php esc_html_e( 'OK', 'post-views-counter' ); ?></a> 384 <a href="#post-views" class="cancel-post-views hide-if-no-js button-cancel"><?php esc_html_e( 'Cancel', 'post-views-counter' ); ?></a> 102 385 </p> 103 386 … … 123 406 return; 124 407 408 // The bulk_edit_posts completion hook is the sole counter writer for 409 // native Bulk Edit, so each updated post gets exactly one write attempt. 410 if ( $this->is_native_bulk_edit_request() ) 411 return; 412 125 413 // break if current user can't edit this post 126 414 if ( ! current_user_can( 'edit_post', $post_id ) ) 127 415 return; 128 416 129 // is post viewsset417 // is the views total set 130 418 if ( ! isset( $_POST['post_views'] ) ) 131 return;132 133 $post_views = $this->sanitize_post_views_input( $_POST['post_views'] );134 135 if ( is_null( $post_views ) )136 419 return; 137 420 … … 163 446 164 447 // validate data 165 if ( ! isset( $_POST['pvc_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pvc_nonce'] ) ), 'post_views_count' ) ) 166 return; 167 168 $current_post_views = null; 169 170 if ( isset( $_POST['current_post_views'] ) ) 171 $current_post_views = $this->sanitize_post_views_input( $_POST['current_post_views'] ); 172 173 // unchanged post views value? 174 if ( ! is_null( $current_post_views ) && $post_views === $current_post_views ) 175 return; 176 177 // update post views 178 pvc_update_post_views( $post_id, $post_views ); 179 180 do_action( 'pvc_after_update_post_views_count', $post_id ); 448 if ( ! isset( $_POST['pvc_nonce'] ) || ! is_scalar( $_POST['pvc_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( (string) $_POST['pvc_nonce'] ) ), 'post_views_count' ) ) 449 return; 450 451 // The submitted total belongs to the post the form was rendered for. 452 // Another post saved during the same request never receives it. 453 if ( ! $this->is_submitted_post( $post_id ) ) 454 return; 455 456 $updates = $this->get_submitted_counter_totals(); 457 458 if ( is_null( $updates ) || empty( $updates ) ) 459 return; 460 461 // Quick Edit belongs to the list column; the edit screen does not. 462 if ( $this->is_quick_edit_request() ? ! $this->can_update_post_counter_totals( $post_id ) : ! $this->can_edit_post_counter_in_editor( $post_id ) ) 463 return; 464 465 $this->update_post_counter_totals( $post_id, $updates ); 181 466 } 182 467 … … 231 516 * Register sortable post views column. 232 517 * 518 * The column sorts natively, descending first. 519 * 233 520 * @param array $columns 234 521 * @return array … … 236 523 public function register_sortable_custom_column( $columns ) { 237 524 global $post_type; 238 525 239 526 // get main instance 240 527 $pvc = Post_Views_Counter(); … … 250 537 251 538 // add new sortable column 252 $columns['post_views'] = 'post_views';539 $columns['post_views'] = [ 'post_views', true ]; 253 540 254 541 return $columns; 542 } 543 544 /** 545 * Prepare a native Views sort on a managed admin post list: keep posts 546 * without a stored total listed and add the deterministic ID tie-break. 547 * 548 * @param WP_Query $query Query object. 549 * @return void 550 */ 551 public function prepare_admin_list_sort( $query ) { 552 if ( ! $this->is_admin_post_list_query( $query ) ) 553 return; 554 555 $orderby = $query->get( 'orderby' ); 556 557 if ( ! is_string( $orderby ) || sanitize_key( $orderby ) !== 'post_views' ) 558 return; 559 560 $order = $query->get( 'order' ); 561 $order = is_scalar( $order ) ? strtoupper( trim( (string) $order ) ) : ''; 562 $order = $order === 'ASC' ? 'ASC' : 'DESC'; 563 $metric_query = [ 'period' => 'total', 'hide_empty' => false ]; 564 565 $query->set( 'orderby', 'post_views' ); 566 $query->set( 'order', $order ); 567 $query->set( 'views_query', $metric_query ); 568 $query->query['orderby'] = 'post_views'; 569 $query->query['order'] = $order; 570 $query->query['views_query'] = $metric_query; 571 572 // Posts with equal totals keep a stable order across pages. 573 $query->pvc_admin_column_sort = 'views'; 574 } 575 576 /** 577 * Check whether the current query is the enabled Core post-list query. 578 * 579 * @param mixed $query Query object. 580 * @return bool 581 */ 582 private function is_admin_post_list_query( $query ) { 583 global $pagenow; 584 585 if ( ! is_admin() || ! ( $query instanceof WP_Query ) || ! $query->is_main_query() || ! in_array( $pagenow, [ 'edit.php', 'upload.php' ], true ) ) 586 return false; 587 588 $pvc = Post_Views_Counter(); 589 590 if ( empty( $pvc->options['display']['post_views_column'] ) || apply_filters( 'pvc_admin_display_post_views', true ) === false ) 591 return false; 592 593 $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; 594 $post_type = $query->get( 'post_type' ); 595 596 if ( ! is_string( $post_type ) || $post_type === '' ) 597 $post_type = $screen && ! empty( $screen->post_type ) ? $screen->post_type : ( $pagenow === 'upload.php' ? 'attachment' : 'post' ); 598 599 return in_array( $post_type, (array) $pvc->options['general']['post_types_count'], true ); 255 600 } 256 601 … … 281 626 282 627 // add post views column 283 $columns['post_views'] = '<span class="pvc-views-header" title="' . esc_attr__( 'Post Views', 'post-views-counter' ) . '"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor"><path d="M12 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1ZM6.5 6a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V6ZM2 9a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V9Z" /></svg><span class="screen-reader-text">' . esc_attr__( 'Post Views', 'post-views-counter' ) . '</span></span>';628 $columns['post_views'] = $this->get_admin_column_header_markup(); 284 629 285 630 // restore date column … … 295 640 296 641 /** 642 * Render the compact statistics-icon Views header. WordPress wraps it in 643 * the native sort link. 644 * 645 * @return string 646 */ 647 private function get_admin_column_header_markup() { 648 $label = __( 'Views', 'post-views-counter' ); 649 650 return '<span class="pvc-views-header" data-pvc-tooltip="' . esc_attr( $label ) . '">' . Post_Views_Counter()->functions->get_counter_icon_svg() . '<span class="screen-reader-text">' . esc_html( $label ) . '</span></span>'; 651 } 652 653 /** 297 654 * Add post views column content. 298 655 * … … 303 660 public function add_new_column_content( $column_name, $id ) { 304 661 if ( $column_name === 'post_views' ) { 662 // check if user can see stats 663 if ( apply_filters( 'pvc_admin_display_post_views', true, $id ) === false ) { 664 echo $this->get_restricted_metric_markup(); 665 return; 666 } 667 305 668 // get total post views 306 669 $count = (int) pvc_get_post_views( $id ); 307 308 // check if user can see stats309 if ( apply_filters( 'pvc_admin_display_post_views', true, $id ) === false ) {310 echo '—';311 return;312 }313 670 314 671 // get post title … … 319 676 320 677 // get post type labels 678 $post_type_labels = null; 321 679 $post_type_object = get_post_type_object( get_post_type( $id ) ); 322 680 … … 329 687 } 330 688 331 // clickable link (modal opening handled via JavaScript) 332 echo '<a href="#" class="pvc-view-chart" data-post-id="' . esc_attr( $id ) . '" data-post-title="' . esc_attr( $post_title ) . '" data-post-views="' . esc_attr( $count ) . '">' . esc_html( $count ) . '</a>'; 689 echo $this->get_column_metric_markup( $count, $id, $post_title, $this->current_user_can_view_post_chart( $id ) ); 333 690 } 691 } 692 693 /** 694 * Check whether the current user may open a post's Views chart: the post 695 * type's list-screen capability plus read access to the post. Authors and 696 * contributors keep the chart for other users' posts they can see in the 697 * list; private posts and drafts they cannot read stay closed. 698 * 699 * @param int|WP_Post $post Post ID or object. 700 * @return bool 701 */ 702 public function current_user_can_view_post_chart( $post ) { 703 $post = get_post( $post ); 704 705 if ( ! $post ) 706 return false; 707 708 $post_type_object = get_post_type_object( $post->post_type ); 709 710 return $post_type_object && current_user_can( $post_type_object->cap->edit_posts ) && current_user_can( 'read_post', $post->ID ); 711 } 712 713 /** 714 * Render the Views value, keeping the raw total for Quick Edit. 715 * 716 * @param int $value Views total. 717 * @param int $post_id Post ID. 718 * @param string $post_title Post title. 719 * @param bool $can_open_chart Whether the current user may open the chart. 720 * @return string 721 */ 722 private function get_column_metric_markup( $value, $post_id, $post_title, $can_open_chart ) { 723 $label = __( 'Views', 'post-views-counter' ); 724 $value = (int) $value; 725 $formatted = number_format_i18n( $value ); 726 727 // Quick Edit reads the raw total, never the locale-formatted text. 728 $data_views = ' data-post-views="' . esc_attr( $value ) . '"'; 729 730 if ( ! $can_open_chart ) 731 return '<span class="pvc-column-metric-value"' . $data_views . '><span aria-hidden="true">' . esc_html( $formatted ) . '</span><span class="screen-reader-text"> ' . esc_html( sprintf( __( '%1$s: %2$s.', 'post-views-counter' ), $label, $formatted ) ) . '</span></span>'; 732 733 // A link whose visible text is only a number still needs an accessible 734 // name. The tooltip is a data attribute, so it never replaces that name 735 // or wraps the link in a tooltip role. 736 $tooltip = sprintf( __( 'Total Views: %s', 'post-views-counter' ), $formatted ); 737 $accessible_label = sprintf( __( '%1$s: %2$s. Open chart.', 'post-views-counter' ), $label, $formatted ); 738 739 return '<a href="#" class="pvc-view-chart" data-post-id="' . esc_attr( $post_id ) . '" data-post-title="' . esc_attr( $post_title ) . '" data-pvc-tooltip="' . esc_attr( $tooltip ) . '"' . $data_views . ' aria-label="' . esc_attr( $accessible_label ) . '">' . esc_html( $formatted ) . '</a>'; 740 } 741 742 /** 743 * Render a count-free restricted-state value for the admin column. 744 * 745 * @return string 746 */ 747 private function get_restricted_metric_markup() { 748 return '<span class="pvc-column-metric-value"><span aria-hidden="true">—</span><span class="screen-reader-text"> ' . esc_html__( 'View statistics are restricted.', 'post-views-counter' ) . '</span></span>'; 334 749 } 335 750 … … 375 790 <fieldset class="inline-edit-col-left"> 376 791 <div id="inline-edit-post_views" class="inline-edit-col"> 792 <?php 793 // The Quick Edit template is rendered once and reused for every 794 // row, so the template-level marker records whether the field may 795 // ever be enabled. 796 ?> 377 797 <label class="inline-edit-group"> 378 <span class="title"><?php _e( 'PostViews', 'post-views-counter' ); ?></span>798 <span class="title"><?php esc_html_e( 'Views', 'post-views-counter' ); ?></span> 379 799 <?php if ( $allow_edit === true && $allow_edit_condition === true ) { ?> 380 <span class="input-text-wrap"><input type=" text" name="post_views" class="title text" value=""></span>800 <span class="input-text-wrap"><input type="number" min="0" step="1" inputmode="numeric" name="post_views" class="title text" value="" data-pvc-editable="1"></span> 381 801 <input type="hidden" name="current_post_views" value="" /> 382 <?php wp_nonce_field( 'post_views_count', 'pvc_nonce' ); ?>383 802 <?php } else { ?> 384 <span class="input-text-wrap"><input type=" text" name="post_views" class="title text" value="" disabled readonly /></span>803 <span class="input-text-wrap"><input type="number" min="0" step="1" inputmode="numeric" name="post_views" class="title text" value="" disabled readonly /></span> 385 804 <?php } ?> 386 805 </label> 806 <?php if ( $allow_edit === true && $allow_edit_condition === true ) wp_nonce_field( 'post_views_count', 'pvc_nonce' ); ?> 387 807 </div> 388 808 </fieldset> … … 391 811 392 812 /** 813 * Apply Bulk Edit counter totals after WordPress has finished its own bulk 814 * update. Only the IDs WordPress actually updated are written, so a locked 815 * or skipped post never receives a counter change. 816 * 817 * @param array $updated Post IDs WordPress updated. 818 * @param array $shared_post_data Submitted bulk fields. 819 * @return void 820 */ 821 public function bulk_edit_post_counters( $updated, $shared_post_data ) { 822 if ( ! is_array( $updated ) || ! is_array( $shared_post_data ) ) 823 return; 824 825 // Only the submitted bulk fields are considered, never ambient request data. 826 if ( ! array_key_exists( 'post_views', $shared_post_data ) ) 827 return; 828 829 // A request without the plugin's own bulk nonce is not one of ours. 830 if ( ! isset( $shared_post_data['pvc_nonce'] ) || ! is_scalar( $shared_post_data['pvc_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( (string) $shared_post_data['pvc_nonce'] ) ), 'post_views_count' ) ) 831 return; 832 833 $updates = $this->get_submitted_counter_totals( $shared_post_data ); 834 835 // Blank means no change. 836 if ( is_array( $updates ) && empty( $updates ) ) 837 return; 838 839 $post_ids = array_values( array_filter( array_unique( array_map( 'absint', $updated ) ) ) ); 840 $pvc = Post_Views_Counter(); 841 $rejected = is_null( $updates ) 842 || empty( $pvc->options['display']['restrict_edit_views'] ) 843 || ! current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) ); 844 845 if ( $rejected ) { 846 $this->set_bulk_counter_result( 0, count( $post_ids ) ); 847 848 return; 849 } 850 851 $post_types = (array) $pvc->options['general']['post_types_count']; 852 $succeeded = 0; 853 $failed = 0; 854 855 foreach ( $post_ids as $post_id ) { 856 if ( ! in_array( get_post_type( $post_id ), $post_types, true ) || ! $this->can_update_post_counter_totals( $post_id ) || ! $this->update_post_counter_totals( $post_id, $updates ) ) 857 $failed++; 858 else 859 $succeeded++; 860 } 861 862 $this->set_bulk_counter_result( $succeeded, $failed ); 863 } 864 865 /** 866 * Record one request-local Bulk Edit counter outcome and arm the narrowly 867 * scoped redirect filter that reports it. No persistent state is stored. 868 * 869 * @param int $updated Successful counter writes. 870 * @param int $failed Failed counter writes. 871 * @return void 872 */ 873 private function set_bulk_counter_result( $updated, $failed ) { 874 $this->bulk_counter_result = [ 'updated' => (int) $updated, 'failed' => (int) $failed ]; 875 876 add_filter( 'wp_redirect', [ $this, 'add_bulk_counter_redirect_args' ] ); 877 } 878 879 /** 880 * Append sanitized counter outcome counts to the matching bulk redirect. 881 * 882 * @param string $location Redirect location. 883 * @return string 884 */ 885 public function add_bulk_counter_redirect_args( $location ) { 886 if ( is_null( $this->bulk_counter_result ) || ! is_string( $location ) || $location === '' ) 887 return $location; 888 889 $path = wp_parse_url( $location, PHP_URL_PATH ); 890 891 // Only the post-list redirect that ends this bulk request is touched. 892 if ( ! is_string( $path ) || basename( $path ) !== 'edit.php' ) 893 return $location; 894 895 $result = $this->bulk_counter_result; 896 $this->bulk_counter_result = null; 897 898 remove_filter( 'wp_redirect', [ $this, 'add_bulk_counter_redirect_args' ] ); 899 900 if ( $result['updated'] < 1 && $result['failed'] < 1 ) 901 return $location; 902 903 return add_query_arg( [ 'pvc_counters_updated' => $result['updated'], 'pvc_counters_failed' => $result['failed'] ], $location ); 904 } 905 906 /** 907 * Report the Bulk Edit counter outcome on the resulting list page. 908 * 909 * WordPress content updates already completed, so a counter failure is 910 * reported truthfully instead of implying the bulk operation was cancelled. 911 * 912 * @global string $pagenow 913 * 914 * @return void 915 */ 916 public function bulk_counter_admin_notice() { 917 global $pagenow; 918 919 if ( $pagenow !== 'edit.php' || ( ! isset( $_GET['pvc_counters_updated'] ) && ! isset( $_GET['pvc_counters_failed'] ) ) ) 920 return; 921 922 $updated = isset( $_GET['pvc_counters_updated'] ) && is_scalar( $_GET['pvc_counters_updated'] ) ? absint( wp_unslash( $_GET['pvc_counters_updated'] ) ) : 0; 923 $failed = isset( $_GET['pvc_counters_failed'] ) && is_scalar( $_GET['pvc_counters_failed'] ) ? absint( wp_unslash( $_GET['pvc_counters_failed'] ) ) : 0; 924 925 if ( $updated < 1 && $failed < 1 ) 926 return; 927 928 $messages = []; 929 930 if ( $updated > 0 ) 931 $messages[] = sprintf( _n( 'Counter totals updated for %s post.', 'Counter totals updated for %s posts.', $updated, 'post-views-counter' ), number_format_i18n( $updated ) ); 932 933 if ( $failed > 0 ) 934 $messages[] = sprintf( _n( 'Counter totals could not be updated for %s post.', 'Counter totals could not be updated for %s posts.', $failed, 'post-views-counter' ), number_format_i18n( $failed ) ); 935 936 echo '<div class="notice notice-' . ( $failed > 0 ? 'error' : 'success' ) . ' is-dismissible"><p>' . esc_html( implode( ' ', $messages ) ) . '</p></div>'; 937 } 938 939 /** 940 * Let WordPress strip the Bulk Edit outcome arguments from the list URL, so 941 * the notice is not shown again on reload. 942 * 943 * @param array $args Removable query arguments. 944 * @return array 945 */ 946 public function add_removable_query_args( $args ) { 947 if ( ! is_array( $args ) ) 948 return $args; 949 950 $args[] = 'pvc_counters_updated'; 951 $args[] = 'pvc_counters_failed'; 952 953 return $args; 954 } 955 956 /** 393 957 * Bulk save post views. 958 * 959 * Deprecated for the shipped UI: native Bulk Edit now writes counter totals 960 * from the bulk_edit_posts completion hook. The endpoint remains registered, 961 * with unchanged security behavior, for compatibility. 394 962 * 395 963 * @return void … … 402 970 exit; 403 971 404 $count = isset( $_POST['post_views'] ) ? $this->sanitize_post_views_input( $_POST['post_views'] ) : null;405 406 972 // check post ids 407 $post_ids = ( ! empty( $_POST['post_ids'] ) && is_array( $_POST['post_ids'] ) ) ? array_map( 'absint', wp_unslash( $_POST['post_ids'] ) ) : []; 408 409 if ( is_null( $count ) ) 410 exit; 973 $post_ids = ( ! empty( $_POST['post_ids'] ) && is_array( $_POST['post_ids'] ) ) ? array_values( array_filter( array_unique( array_map( 'absint', wp_unslash( $_POST['post_ids'] ) ) ) ) ) : []; 974 $updates = $this->get_submitted_counter_totals(); 975 976 if ( is_null( $updates ) ) 977 wp_send_json_error( [ 'message' => __( 'Invalid counter totals.', 'post-views-counter' ) ] ); 411 978 412 979 // allow editing … … 418 985 // break if views editing not allowed or editing condition not met 419 986 if ( $allow_edit === false || $allow_edit_condition === false ) 420 exit;987 wp_send_json_error( [ 'message' => __( 'Permission denied.', 'post-views-counter' ) ] ); 421 988 422 989 $post_types = (array) $pvc->options['general']['post_types_count']; 423 990 424 991 // any post ids? 425 if ( ! empty( $post_ids ) ) { 992 $updated = 0; 993 $failed = 0; 994 995 if ( ! empty( $post_ids ) && ! empty( $updates ) ) { 426 996 foreach ( $post_ids as $post_id ) { 427 // break if current user can't edit this post 428 if ( ! current_user_can( 'edit_post', $post_id ) ) 429 continue; 430 431 if ( ! in_array( get_post_type( $post_id ), $post_types, true ) ) 432 continue; 433 434 if ( pvc_update_post_views( $post_id, $count ) !== false ) 435 do_action( 'pvc_after_update_post_views_count', $post_id ); 997 if ( ! in_array( get_post_type( $post_id ), $post_types, true ) || ! $this->can_update_post_counter_totals( $post_id ) || ! $this->update_post_counter_totals( $post_id, $updates ) ) 998 $failed++; 999 else 1000 $updated++; 436 1001 } 437 1002 } 438 1003 439 exit;1004 wp_send_json_success( [ 'updated' => $updated, 'failed' => $failed ] ); 440 1005 } 441 1006 } -
post-views-counter/tags/1.8.0/includes/class-counter.php
r3640258 r3734102 10 10 */ 11 11 class Post_Views_Counter_Counter { 12 const REST_MAX_TARGETS = 100; 13 const STORAGE_MAX_PAYLOAD_BYTES = 15920; 14 const STORAGE_MAX_COOKIE_CHUNKS = 4; 15 const STORAGE_MAX_BUCKETS = 8; 16 const STORAGE_MAX_MEMBERS = 1000; 12 17 13 18 private $storage = []; … … 15 20 private $queue = []; 16 21 private $queue_mode = false; 17 private $db_insert_values = '';22 private $db_insert_values = []; 18 23 private $cookie = []; 24 private $pending_storage_commit = null; 25 private $pending_session_created = null; 26 private $window_created_candidate = false; 27 private $last_cache_flush_status = 'idle'; 19 28 20 29 /** … … 98 107 99 108 foreach ( $ids as $id ) { 100 $counted[$id] = ! ( $this->check_post( $id ) === null );109 $counted[$id] = ! ( $this->check_post( $id, [], true ) === null ); 101 110 } 102 111 … … 219 228 * @param int $post_id 220 229 * @param array $content_data 230 * @param bool $views_only 221 231 * 222 232 * @return null|int 223 233 */ 224 public function check_post( $post_id = 0, $content_data = [] ) { 234 public function check_post( $post_id = 0, $content_data = [], $views_only = false ) { 235 $this->reset_pending_count_state(); 236 225 237 // force check cookie in short init mode 226 238 if ( defined( 'SHORTINIT' ) && SHORTINIT ) … … 271 283 } 272 284 285 $visit_increment = 0; 286 287 if ( ! $views_only && $this->window_created_candidate ) { 288 $availability = $pvc->visits instanceof Post_Views_Counter_Visits ? $pvc->visits->get_visits_availability() : [ 'writable' => false ]; 289 290 if ( ! empty( $availability['writable'] ) ) 291 $visit_increment = 1; 292 } 293 273 294 // filter visit counting 274 295 $count_visit = (bool) apply_filters( 'pvc_count_visit', $count_visit, $post_id, $user_id, $user_ip, 'post', $hook_content_data ); … … 279 300 do_action( 'pvc_before_count_visit', $post_id, $user_id, $user_ip, 'post', $hook_content_data ); 280 301 281 return $this->count_visit( $post_id ); 282 } 302 $result = $this->count_visit( $post_id, $visit_increment ); 303 304 if ( $result !== null ) { 305 if ( $views_only ) 306 $this->discard_pending_storage(); 307 else 308 $this->commit_pending_storage(); 309 310 return $result; 311 } 312 } 313 314 $this->discard_pending_storage(); 315 316 return null; 283 317 } 284 318 … … 483 517 $storage_data = []; 484 518 519 $storage_data = $this->mark_storage_capability( $storage_data, isset( $_POST['storage_capable'] ) ? $_POST['storage_capable'] : null ); 520 485 521 echo wp_json_encode( 486 522 [ … … 558 594 else 559 595 $storage_data = []; 596 597 $storage_data = $this->mark_storage_capability( $storage_data, $request->get_param( 'storage_capable' ) ); 560 598 561 599 return [ … … 733 771 * @return array 734 772 */ 735 public function build_session_storage_payload( $storage_state, $content_id = 0, $content_type = 'post', $default_expiration = 0, $current_time = 0 ) {736 $session_state = $this->create_session_storage_state( $storage_state, $content_id, $content_type, $default_expiration, $current_time );773 public function build_session_storage_payload( $storage_state, $content_id = 0, $content_type = 'post', $default_expiration = 0, $current_time = 0, $emit_hook = true ) { 774 $session_state = $this->create_session_storage_state( $storage_state, $content_id, $content_type, $default_expiration, $current_time, $emit_hook ); 737 775 738 776 return $this->get_public_session_storage_payload( $session_state ); … … 757 795 758 796 foreach ( $storage_states as $storage_state ) { 797 if ( is_array( $storage_state ) && isset( $storage_state['_pvc_storage_capable'] ) && $storage_state['_pvc_storage_capable'] === false ) { 798 $merged_state['_pvc_storage_capable'] = false; 799 continue; 800 } 801 759 802 if ( ! $this->is_normalized_storage_state( $storage_state ) || ! $storage_state['is_valid'] ) 760 803 continue; … … 791 834 } 792 835 } 836 } 837 838 if ( count( $merged_state['visited'] ) > self::STORAGE_MAX_BUCKETS ) { 839 $merged_state['format'] = 'invalid'; 840 $merged_state['is_valid'] = false; 841 $merged_state['_pvc_storage_capable'] = false; 842 843 return $merged_state; 793 844 } 794 845 … … 803 854 $merged_state['needs_writeback'] = false; 804 855 805 return $ merged_state;856 return $this->limit_storage_state_members( $merged_state ); 806 857 } 807 858 … … 811 862 } 812 863 813 return $merged_state; 864 return $this->limit_storage_state_members( $merged_state ); 865 } 866 867 /** 868 * Keep merged storage membership within the request payload budget. 869 * 870 * @param array $storage_state Normalized storage state. 871 * @return array 872 */ 873 private function limit_storage_state_members( $storage_state ) { 874 $member_count = 0; 875 876 foreach ( $storage_state['visited'] as $bucket => $bucket_members ) { 877 foreach ( array_keys( $bucket_members ) as $content_id ) { 878 $member_count++; 879 880 if ( $member_count <= self::STORAGE_MAX_MEMBERS ) 881 continue; 882 883 unset( $storage_state['visited'][$bucket][$content_id], $storage_state['legacy']['expirations'][$bucket][$content_id] ); 884 } 885 } 886 887 return $storage_state; 814 888 } 815 889 … … 825 899 * @return array 826 900 */ 827 private function create_session_storage_state( $storage_state, $content_id = 0, $content_type = 'post', $default_expiration = 0, $current_time = 0 ) {901 private function create_session_storage_state( $storage_state, $content_id = 0, $content_type = 'post', $default_expiration = 0, $current_time = 0, $emit_hook = true ) { 828 902 $content_type = $this->normalize_storage_bucket( $content_type ); 829 903 $content_id = (int) $content_id; … … 848 922 849 923 // new session created -- entrance/visit hook for the triggering content item 850 if ( $content_id > 0 ) {924 if ( $content_id > 0 && $emit_hook ) { 851 925 /** 852 926 * Fires when a new anonymous session is created. … … 869 943 $session_state['needs_writeback'] = false; 870 944 871 if ( $content_id > 0 ) 945 if ( $content_id > 0 && ! isset( $session_state['visited'][$content_type][$content_id] ) ) { 946 $member_count = 0; 947 948 foreach ( $session_state['visited'] as $bucket_members ) 949 $member_count += count( $bucket_members ); 950 951 if ( $member_count >= self::STORAGE_MAX_MEMBERS ) { 952 foreach ( $session_state['visited'] as $bucket => $bucket_members ) { 953 if ( empty( $bucket_members ) ) 954 continue; 955 956 $remove_id = key( $bucket_members ); 957 unset( $session_state['visited'][$bucket][$remove_id] ); 958 break; 959 } 960 } 961 872 962 $session_state['visited'][$content_type][$content_id] = true; 963 } 873 964 874 965 return $session_state; … … 920 1011 921 1012 /** 1013 * Emit one browser storage cookie chunk. 1014 * 1015 * Single emission point for every counter cookie so path, domain, secure, 1016 * httponly and SameSite stay identical for writes and deletions. The plugin 1017 * requires PHP 7.4, so the options-array form is always available. 1018 * 1019 * @param string $name Full cookie name including its chunk suffix. 1020 * @param string $value Chunk value; an empty string deletes the chunk. 1021 * @param int $expires Expiry timestamp; 1 deletes the chunk. 1022 * 1023 * @return bool 1024 */ 1025 private function set_storage_cookie( $name, $value, $expires ) { 1026 return $this->send_cookie( 1027 $name, 1028 (string) $value, 1029 [ 1030 'expires' => (int) $expires, 1031 'path' => COOKIEPATH, 1032 'domain' => COOKIE_DOMAIN, 1033 'secure' => is_ssl(), 1034 'httponly' => false, 1035 'samesite' => 'LAX' 1036 ] 1037 ); 1038 } 1039 1040 /** 1041 * Transport seam for cookie emission. 1042 * 1043 * Isolated so the prepared attributes can be observed without a real HTTP 1044 * response. Nothing but set_storage_cookie() may call it. 1045 * 1046 * @param string $name Cookie name. 1047 * @param string $value Cookie value. 1048 * @param array $options PHP 7.4-compatible setcookie() options array. 1049 * 1050 * @return bool 1051 */ 1052 protected function send_cookie( $name, $value, $options ) { 1053 return setcookie( $name, $value, $options ); 1054 } 1055 1056 /** 922 1057 * Clear stale cookie chunks that are no longer used by the current payload. 923 1058 * 924 1059 * @param string $cookie_name 925 1060 * @param int $valid_chunk_count 926 * @param bool $php_at_least_73927 1061 * 928 1062 * @return void 929 1063 */ 930 private function clear_stale_cookie_chunks( $cookie_name, $valid_chunk_count , $php_at_least_73) {1064 private function clear_stale_cookie_chunks( $cookie_name, $valid_chunk_count ) { 931 1065 if ( ! isset( $_COOKIE[$cookie_name] ) || ! is_array( $_COOKIE[$cookie_name] ) ) 932 1066 return; … … 938 1072 continue; 939 1073 940 if ( $php_at_least_73 ) { 941 setcookie( 942 $cookie_name . '[' . $chunk_index . ']', 943 '', 944 [ 945 'expires' => 1, 946 'path' => COOKIEPATH, 947 'domain' => COOKIE_DOMAIN, 948 'secure' => is_ssl(), 949 'httponly' => false, 950 'samesite' => 'LAX' 951 ] 952 ); 953 } else { 954 setcookie( $cookie_name . '[' . $chunk_index . ']', '', 1, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), false ); 955 } 1074 $this->set_storage_cookie( $cookie_name . '[' . $chunk_index . ']', '', 1 ); 956 1075 } 957 1076 } … … 1004 1123 $content_type = $this->normalize_storage_bucket( $content_type ); 1005 1124 $storage_payloads = $this->parse_storage_payload_map( $storage_data_all ); 1125 1126 if ( isset( $storage_payloads['_pvc_storage_capable'] ) && $storage_payloads['_pvc_storage_capable'] === false ) { 1127 $state = $this->get_empty_storage_state(); 1128 $state['_pvc_storage_capable'] = false; 1129 1130 return $state; 1131 } 1006 1132 1007 1133 if ( empty( $storage_payloads ) ) { … … 1041 1167 return []; 1042 1168 1169 if ( strlen( $storage_data_all ) > self::STORAGE_MAX_PAYLOAD_BYTES ) 1170 return [ '_pvc_storage_capable' => false ]; 1171 1043 1172 $decoded_payloads = json_decode( stripslashes( $storage_data_all ), true, 8 ); 1044 1173 1045 1174 if ( json_last_error() !== JSON_ERROR_NONE || ! is_array( $decoded_payloads ) ) 1046 1175 return []; 1047 } elseif ( is_array( $storage_data_all ) ) 1176 1177 if ( count( $decoded_payloads ) > self::STORAGE_MAX_BUCKETS ) 1178 return [ '_pvc_storage_capable' => false ]; 1179 } elseif ( is_array( $storage_data_all ) ) { 1180 if ( count( $storage_data_all ) > self::STORAGE_MAX_BUCKETS ) 1181 return [ '_pvc_storage_capable' => false ]; 1182 1048 1183 $decoded_payloads = $storage_data_all; 1049 else1184 } else 1050 1185 return []; 1051 1186 … … 1061 1196 1062 1197 /** 1063 * Check whether the active Proplugin supports session payload writes.1198 * Check whether the active extension plugin supports session payload writes. 1064 1199 * 1065 1200 * @return bool … … 1080 1215 * Check whether session payload writes are enabled. 1081 1216 * 1082 * Session payload writes are the default for PVC-only installs. When Pro is active,1083 * PVC uses Pro's explicit capability declaration and allows this filter to override1084 * the computed default for controlled testing or emergency rollback.1217 * Session payload writes are the default for Core-only installs. With an 1218 * active extension, its declared capability determines the default. This 1219 * filter can override it for controlled testing or emergency rollback. 1085 1220 * 1086 1221 * @return bool … … 1118 1253 ksort( $bucket_expirations, SORT_NUMERIC ); 1119 1254 1255 while ( count( $bucket_expirations ) > self::STORAGE_MAX_MEMBERS || strlen( $this->serialize_legacy_cookie_payload( $bucket_expirations ) ) > self::STORAGE_MAX_PAYLOAD_BYTES ) { 1256 $remove_id = key( $bucket_expirations ); 1257 1258 if ( (int) $remove_id === $content_id ) { 1259 next( $bucket_expirations ); 1260 $remove_id = key( $bucket_expirations ); 1261 } 1262 1263 if ( $remove_id === null ) 1264 break; 1265 1266 unset( $bucket_expirations[$remove_id] ); 1267 reset( $bucket_expirations ); 1268 } 1269 1120 1270 return $bucket_expirations; 1121 1271 } … … 1151 1301 ]; 1152 1302 $cookie_chunks = str_split( $payload, 3980 ); 1303 1304 if ( count( $cookie_chunks ) > self::STORAGE_MAX_COOKIE_CHUNKS ) 1305 return [ 'name' => [], 'value' => [], 'expiry' => [] ]; 1306 1153 1307 $cookie_expiration = max( $bucket_expirations ); 1154 1308 … … 1297 1451 private function combine_cookie_chunks( $cookie_chunks ) { 1298 1452 $chunks = []; 1453 $payload_bytes = 0; 1454 1455 if ( ! is_array( $cookie_chunks ) || count( $cookie_chunks ) > self::STORAGE_MAX_COOKIE_CHUNKS ) 1456 return '__pvc_invalid_storage_payload__'; 1457 1458 ksort( $cookie_chunks, SORT_NUMERIC ); 1459 1460 if ( ! empty( $cookie_chunks ) && array_keys( $cookie_chunks ) !== range( 0, count( $cookie_chunks ) - 1 ) ) 1461 return '__pvc_invalid_storage_payload__'; 1299 1462 1300 1463 foreach ( $cookie_chunks as $chunk ) { 1301 if ( is_scalar( $chunk ) ) 1302 $chunks[] = (string) $chunk; 1464 if ( ! is_scalar( $chunk ) ) 1465 return '__pvc_invalid_storage_payload__'; 1466 1467 $chunk = (string) $chunk; 1468 $payload_bytes += strlen( $chunk ); 1469 1470 if ( $payload_bytes > self::STORAGE_MAX_PAYLOAD_BYTES ) 1471 return '__pvc_invalid_storage_payload__'; 1472 1473 $chunks[] = $chunk; 1303 1474 } 1304 1475 … … 1331 1502 $state = $this->get_empty_storage_state(); 1332 1503 1333 if ( is_array( $storage_data ) ) 1504 if ( is_array( $storage_data ) ) { 1505 $encoded_storage = wp_json_encode( $storage_data ); 1506 1507 if ( ! is_string( $encoded_storage ) || strlen( $encoded_storage ) > self::STORAGE_MAX_PAYLOAD_BYTES ) { 1508 $state['format'] = 'invalid'; 1509 $state['is_valid'] = false; 1510 $state['_pvc_storage_capable'] = false; 1511 1512 return $state; 1513 } 1514 1334 1515 return $this->normalize_json_storage_state( $storage_data, $content_type ); 1516 } 1335 1517 1336 1518 if ( ! is_scalar( $storage_data ) ) { … … 1342 1524 1343 1525 $storage_data = trim( (string) $storage_data ); 1526 1527 if ( $storage_data === '__pvc_invalid_storage_payload__' ) { 1528 $state['format'] = 'invalid'; 1529 $state['is_valid'] = false; 1530 $state['_pvc_storage_capable'] = false; 1531 1532 return $state; 1533 } 1534 1535 if ( strlen( $storage_data ) > self::STORAGE_MAX_PAYLOAD_BYTES ) { 1536 $state['format'] = 'invalid'; 1537 $state['is_valid'] = false; 1538 $state['_pvc_storage_capable'] = false; 1539 1540 return $state; 1541 } 1344 1542 1345 1543 if ( $storage_data === '' ) … … 1403 1601 $expires_at = isset( $storage_data['expires_at'] ) ? (int) $storage_data['expires_at'] : 0; 1404 1602 1405 if ( $session_id === '' || $started_at <= 0 || $expires_at <= 0 || $expires_at < $started_at || ! isset( $storage_data['visited'] ) || ! is_array( $storage_data['visited'] ) ) {1603 if ( $session_id === '' || $started_at <= 0 || $expires_at <= 0 || $expires_at < $started_at || ! isset( $storage_data['visited'] ) || ! is_array( $storage_data['visited'] ) || count( $storage_data['visited'] ) > self::STORAGE_MAX_BUCKETS ) { 1406 1604 $state['format'] = 'invalid'; 1407 1605 $state['is_valid'] = false; 1606 1607 if ( isset( $storage_data['visited'] ) && is_array( $storage_data['visited'] ) && count( $storage_data['visited'] ) > self::STORAGE_MAX_BUCKETS ) 1608 $state['_pvc_storage_capable'] = false; 1408 1609 1409 1610 return $state; … … 1433 1634 } 1434 1635 1636 if ( count( $state['visited'] ) > self::STORAGE_MAX_BUCKETS ) { 1637 $state['format'] = 'invalid'; 1638 $state['is_valid'] = false; 1639 $state['_pvc_storage_capable'] = false; 1640 1641 return $state; 1642 } 1643 1644 $member_count = 0; 1645 1646 foreach ( $state['visited'] as $bucket_members ) 1647 $member_count += count( $bucket_members ); 1648 1649 if ( $member_count > self::STORAGE_MAX_MEMBERS ) { 1650 $state['format'] = 'invalid'; 1651 $state['is_valid'] = false; 1652 $state['_pvc_storage_capable'] = false; 1653 } 1654 1435 1655 return $state; 1436 1656 } … … 1459 1679 $state['legacy']['expirations'][$content_type][$content_id] = $expiration; 1460 1680 $valid_items++; 1681 1682 if ( $valid_items > self::STORAGE_MAX_MEMBERS ) { 1683 $state['format'] = 'invalid'; 1684 $state['is_valid'] = false; 1685 $state['_pvc_storage_capable'] = false; 1686 1687 return $state; 1688 } 1461 1689 } 1462 1690 … … 1495 1723 $state['visited'][$content_type][$content_id] = true; 1496 1724 $state['legacy']['expirations'][$content_type][$content_id] = $expiration; 1725 1726 if ( count( $state['visited'][$content_type] ) > self::STORAGE_MAX_MEMBERS ) { 1727 $state['format'] = 'invalid'; 1728 $state['is_valid'] = false; 1729 $state['_pvc_storage_capable'] = false; 1730 1731 return $state; 1732 } 1497 1733 } 1498 1734 … … 1575 1811 return [ 'post' => [] ]; 1576 1812 1813 $buckets = array_slice( $buckets, 0, self::STORAGE_MAX_BUCKETS, true ); 1814 1577 1815 // ensure all bucket values are arrays 1578 1816 foreach ( $buckets as $key => $value ) { … … 1610 1848 */ 1611 1849 private function save_data_storage( $content, $content_type, $content_data ) { 1850 if ( isset( $content_data['_pvc_storage_capable'] ) && $content_data['_pvc_storage_capable'] === false ) { 1851 $this->storage = []; 1852 1853 return true; 1854 } 1855 1612 1856 // get base instance 1613 1857 $pvc = Post_Views_Counter(); … … 1624 1868 } 1625 1869 1626 if ( $this->use_session_storage_payload_writes() ) 1627 $this->storage = $this->build_session_storage_payload( $content_data, $content, $content_type, $expiration, $current_time ); 1870 if ( $this->use_session_storage_payload_writes() ) { 1871 $this->window_created_candidate = $this->storage_state_creates_window( $content_data ); 1872 $this->storage = $this->build_session_storage_payload( $content_data, $content, $content_type, $expiration, $current_time, false ); 1873 $this->prepare_session_created_hook( $this->storage, $content, $content_type ); 1874 } 1628 1875 else 1629 1876 $this->storage = [ $content_type => $this->build_legacy_storage_payload( $content_data, $content, $content_type, $expiration, $current_time ) ]; 1630 1877 1878 $this->pending_storage_commit = [ 'type' => 'response' ]; 1879 1631 1880 return $count_visit; 1632 1881 } … … 1641 1890 */ 1642 1891 private function save_cookie_storage( $content, $content_data ) { 1892 if ( isset( $content_data['_pvc_storage_capable'] ) && $content_data['_pvc_storage_capable'] === false ) { 1893 $this->storage = []; 1894 1895 return true; 1896 } 1897 1643 1898 // early return? 1644 1899 //TODO check this filter in js … … 1665 1920 if ( ! $this->use_session_storage_payload_writes() ) { 1666 1921 $this->storage = $this->build_legacy_cookie_storage_data( $content_data, $cookie_name, $content, 'post', $expiration, $current_time ); 1922 $this->pending_storage_commit = [ 'type' => 'response' ]; 1667 1923 1668 1924 return $count_visit; 1669 1925 } 1670 1926 1671 $session_payload = $this->build_session_storage_payload( $content_data, $content, 'post', $expiration, $current_time ); 1927 $this->window_created_candidate = $this->storage_state_creates_window( $content_data ); 1928 $session_payload = $this->build_session_storage_payload( $content_data, $content, 'post', $expiration, $current_time, false ); 1672 1929 $session_json = wp_json_encode( $session_payload ); 1673 1930 1674 if ( ! is_string( $session_json ) || $session_json === '' ) {1931 if ( ! is_string( $session_json ) || $session_json === '' || strlen( $session_json ) > self::STORAGE_MAX_PAYLOAD_BYTES ) { 1675 1932 $this->storage = []; 1676 1933 … … 1693 1950 1694 1951 $this->storage = $cookies_data; 1952 $this->pending_storage_commit = [ 'type' => 'response' ]; 1953 $this->prepare_session_created_hook( $session_payload, $content, 'post' ); 1695 1954 1696 1955 return $count_visit; … … 1723 1982 // assign cookie name 1724 1983 $cookie_name = 'pvc_visits' . ( is_multisite() ? '_' . get_current_blog_id() : '' ); 1725 $php_at_least_73 = version_compare( phpversion(), '7.3', '>=' );1726 1984 1727 1985 if ( ! $this->use_session_storage_payload_writes() ) { 1728 1986 $legacy_payload = $this->serialize_legacy_cookie_payload( $this->build_legacy_storage_payload( $cookie, $id, 'post', $expiration, $current_time ) ); 1729 1987 $cookies_data = $this->build_legacy_cookie_storage_data( $cookie, $cookie_name, $id, 'post', $expiration, $current_time ); 1730 1731 foreach ( $cookies_data['name'] as $key => $cookie_chunk_name ) { 1732 if ( $php_at_least_73 ) { 1733 setcookie( 1734 $cookie_chunk_name, 1735 $cookies_data['value'][$key], 1736 [ 1737 'expires' => $cookies_data['expiry'][$key], 1738 'path' => COOKIEPATH, 1739 'domain' => COOKIE_DOMAIN, 1740 'secure' => is_ssl(), 1741 'httponly' => false, 1742 'samesite' => 'LAX' 1743 ] 1744 ); 1745 } else { 1746 setcookie( $cookie_chunk_name, $cookies_data['value'][$key], $cookies_data['expiry'][$key], COOKIEPATH, COOKIE_DOMAIN, is_ssl(), false ); 1747 } 1748 } 1749 1750 $this->clear_stale_cookie_chunks( $cookie_name, count( $cookies_data['name'] ), $php_at_least_73 ); 1751 1752 if ( $this->queue_mode ) 1753 $this->cookie = $this->sanitize_cookies_data( $legacy_payload, 'post' ); 1988 $this->pending_storage_commit = [ 1989 'type' => 'cookie', 1990 'cookies' => $cookies_data, 1991 'cookie_name' => $cookie_name, 1992 'normalized_payload' => $legacy_payload 1993 ]; 1754 1994 1755 1995 return $count_visit; 1756 1996 } 1757 1997 1758 $session_payload = $this->build_session_storage_payload( $cookie, $id, 'post', $expiration, $current_time ); 1998 $this->window_created_candidate = $this->storage_state_creates_window( $cookie ); 1999 $session_payload = $this->build_session_storage_payload( $cookie, $id, 'post', $expiration, $current_time, false ); 1759 2000 $session_json = wp_json_encode( $session_payload ); 1760 2001 1761 if ( ! is_string( $session_json ) || $session_json === '' )2002 if ( ! is_string( $session_json ) || $session_json === '' || strlen( $session_json ) > self::STORAGE_MAX_PAYLOAD_BYTES ) 1762 2003 return false; 1763 2004 1764 // check whether php version is at least 7.31765 2005 $cookie_chunks = str_split( $session_json, 3980 ); 1766 2006 $cookie_expiration = (int) $session_payload['expires_at']; 1767 2007 2008 $cookies_data = [ 'name' => [], 'value' => [], 'expiry' => [] ]; 2009 1768 2010 foreach ( $cookie_chunks as $key => $value ) { 1769 if ( $php_at_least_73 ) { 1770 setcookie( 1771 $cookie_name . '[' . $key . ']', 1772 $value, 1773 [ 1774 'expires' => $cookie_expiration, 1775 'path' => COOKIEPATH, 1776 'domain' => COOKIE_DOMAIN, 1777 'secure' => is_ssl(), 1778 'httponly' => false, 1779 'samesite' => 'LAX' 1780 ] 1781 ); 1782 } else { 1783 setcookie( $cookie_name . '[' . $key . ']', $value, $cookie_expiration, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), false ); 1784 } 1785 } 1786 1787 $this->clear_stale_cookie_chunks( $cookie_name, count( $cookie_chunks ), $php_at_least_73 ); 1788 1789 if ( $this->queue_mode ) 1790 $this->cookie = $this->sanitize_cookies_data( $session_json, 'post' ); 2011 $cookies_data['name'][] = $cookie_name . '[' . $key . ']'; 2012 $cookies_data['value'][] = $value; 2013 $cookies_data['expiry'][] = $cookie_expiration; 2014 } 2015 2016 $this->pending_storage_commit = [ 2017 'type' => 'cookie', 2018 'cookies' => $cookies_data, 2019 'cookie_name' => $cookie_name, 2020 'normalized_payload' => $session_json 2021 ]; 2022 $this->prepare_session_created_hook( $session_payload, $id, 'post' ); 1791 2023 1792 2024 return $count_visit; … … 1794 2026 1795 2027 /** 1796 * Count visit. 1797 * 1798 * @param int $post_id 1799 * 1800 * @return int|null 1801 */ 1802 private function count_visit( $post_id ) { 2028 * Reset temporary decision state at every public count operation boundary. 2029 * 2030 * @return void 2031 */ 2032 private function reset_pending_count_state() { 2033 $this->storage = []; 2034 $this->pending_storage_commit = null; 2035 $this->pending_session_created = null; 2036 $this->window_created_candidate = false; 2037 } 2038 2039 /** 2040 * Drop uncommitted browser state after a filtered or failed writer attempt. 2041 * 2042 * @return void 2043 */ 2044 private function discard_pending_storage() { 2045 $this->storage = []; 2046 $this->pending_storage_commit = null; 2047 $this->pending_session_created = null; 2048 $this->window_created_candidate = false; 2049 } 2050 2051 /** 2052 * Commit the prepared browser response/cookie only after writer success. 2053 * 2054 * @return void 2055 */ 2056 private function commit_pending_storage() { 2057 if ( is_array( $this->pending_storage_commit ) && $this->pending_storage_commit['type'] === 'cookie' ) { 2058 $this->emit_cookie_storage( $this->pending_storage_commit ); 2059 $this->cookie = $this->sanitize_cookies_data( $this->pending_storage_commit['normalized_payload'], 'post' ); 2060 } 2061 2062 if ( is_array( $this->pending_session_created ) ) 2063 do_action( 'pvc_session_created', $this->pending_session_created['state'], $this->pending_session_created['content_id'], $this->pending_session_created['content_type'] ); 2064 2065 $this->pending_storage_commit = null; 2066 $this->pending_session_created = null; 2067 $this->window_created_candidate = false; 2068 } 2069 2070 /** 2071 * Emit prepared cookie chunks. 2072 * 2073 * @param array $commit Prepared cookie commit. 2074 * @return void 2075 */ 2076 protected function emit_cookie_storage( $commit ) { 2077 $cookies_data = $commit['cookies']; 2078 2079 foreach ( $cookies_data['name'] as $key => $cookie_chunk_name ) { 2080 $this->set_storage_cookie( $cookie_chunk_name, $cookies_data['value'][$key], $cookies_data['expiry'][$key] ); 2081 } 2082 2083 $this->clear_stale_cookie_chunks( $commit['cookie_name'], count( $cookies_data['name'] ) ); 2084 } 2085 2086 /** 2087 * A logical Visit can start only from empty or expired valid normalized 2088 * session storage. Legacy per-content state cannot prove a global start. 2089 * 2090 * @param mixed $storage_state Normalized state. 2091 * @return bool 2092 */ 2093 private function storage_state_creates_window( $storage_state ) { 2094 if ( ! $this->use_session_storage_payload_writes() || ! $this->is_normalized_storage_state( $storage_state ) || empty( $storage_state['is_valid'] ) ) 2095 return false; 2096 2097 if ( empty( Post_Views_Counter()->options['general']['time_between_counts']['number'] ) ) 2098 return false; 2099 2100 return $storage_state['format'] === 'empty' || ( $storage_state['format'] === 'session' && ! empty( $storage_state['is_expired'] ) ); 2101 } 2102 2103 /** 2104 * Attach the browser's explicit storage capability result to normalized 2105 * request state. Older clients omit the flag and retain legacy behavior. 2106 * 2107 * @param array $storage_state Normalized request storage. 2108 * @param mixed $capable Client capability value. 2109 * @return array 2110 */ 2111 private function mark_storage_capability( $storage_state, $capable ) { 2112 $storage_state = is_array( $storage_state ) ? $storage_state : []; 2113 2114 if ( isset( $storage_state['_pvc_storage_capable'] ) && $storage_state['_pvc_storage_capable'] === false ) 2115 return $storage_state; 2116 2117 if ( $capable !== null ) 2118 $storage_state['_pvc_storage_capable'] = is_bool( $capable ) ? $capable : ! in_array( strtolower( (string) $capable ), [ '0', 'false', 'no' ], true ); 2119 2120 return $storage_state; 2121 } 2122 2123 /** 2124 * Prepare the deferred session-created hook for the triggering tuple. 2125 * 2126 * @param array $payload Public session payload. 2127 * @param int $content_id Content ID. 2128 * @param string $content_type Content type. 2129 * @return void 2130 */ 2131 private function prepare_session_created_hook( $payload, $content_id, $content_type ) { 2132 if ( ! $this->window_created_candidate ) 2133 return; 2134 2135 $state = $this->normalize_storage_state( $payload, $content_type, 'auto' ); 2136 2137 if ( ! $this->is_normalized_storage_state( $state ) || empty( $state['is_valid'] ) || $state['format'] !== 'session' ) 2138 return; 2139 2140 $this->pending_session_created = [ 2141 'state' => $state, 2142 'content_id' => (int) $content_id, 2143 'content_type' => $content_type 2144 ]; 2145 } 2146 2147 /** 2148 * Record one countable event for a post. 2149 * 2150 * Terminology used across the counting pipeline: 2151 * - View: an eligible content impression, written to the `count` column. 2152 * - Visit: the first eligible content item that starts a fixed Count 2153 * Interval, written to the `visits` column. At most one Visit exists per 2154 * interval, so ancillary tuples in the same request receive Views only. 2155 * - Legacy hook terminology predates the Visit metric and uses "visit" to 2156 * mean a countable View event. `count_visit()`, `pvc_count_visit`, 2157 * `pvc_before_count_visit` and `pvc_after_count_visit` all keep that older 2158 * meaning and are unchanged public contracts. 2159 * 2160 * @param int $post_id Post ID. 2161 * @param int $visit_increment Visit delta for this event; 0 for Views-only. 2162 * 2163 * @return int|null Post ID on success, null when the write did not succeed. 2164 */ 2165 private function count_visit( $post_id, $visit_increment = 0 ) { 1803 2166 // increment amount 1804 $ increment_amount = (int) apply_filters( 'pvc_views_increment_amount', 1, $post_id, 'post' );1805 1806 if ( $ increment_amount < 1 )1807 $ increment_amount = 1;2167 $view_increment = (int) apply_filters( 'pvc_views_increment_amount', 1, $post_id, 'post' ); 2168 2169 if ( $view_increment < 1 ) 2170 $view_increment = 1; 1808 2171 1809 2172 // get day, week, month and year … … 1814 2177 'content_id' => $post_id, 1815 2178 'content_type' => 'post', 1816 'increment' => $increment_amount, 1817 'visits' => [ 2179 'increment' => $view_increment, 2180 'visit_increment' => (int) $visit_increment, 2181 'period_buckets' => [ 1818 2182 0 => $date[3] . $date[2] . $date[1], // day like 20140324 1819 2183 1 => $date[4] . $date[0], // week like 201439 … … 1824 2188 ]; 1825 2189 2190 // Backward compatibility only. Replacements registered on the released 2191 // `pvc_count_visit_multi` filter read their period buckets from the 2192 // `visits` key, so it must keep carrying the buckets. It is NOT the new 2193 // Visit metric; that value travels in `visit_increment`. New consumers 2194 // should read `period_buckets`. 2195 $count_data['visits'] = $count_data['period_buckets']; 2196 1826 2197 // attempt to count the visit and check for success 1827 2198 if ( call_user_func( apply_filters( 'pvc_count_visit_multi', [ $this, 'count_visit_multi' ] ), $count_data ) ) { … … 1836 2207 1837 2208 /** 1838 * Prepare values to be inserted into database. 1839 * 1840 * @param array $data 2209 * Public writer for one complete set of period rows. 2210 * 2211 * Accepts the released payload: `content_id`, `content_type`, `increment` 2212 * (the View delta), `visit_increment` (the Visit delta), `period_buckets`, 2213 * and the legacy `visits` alias that still carries period buckets. This must 2214 * fail closed when it is called independently or through a 2215 * `pvc_count_visit_multi` replacement, so it re-derives Visit availability 2216 * rather than trusting the caller. 2217 * 2218 * @param array $data Count payload. 1841 2219 * 1842 2220 * @return bool … … 1847 2225 return false; 1848 2226 1849 $success = true; 1850 1851 foreach ( $data['visits'] as $type => $period ) { 1852 // hit the database directly and check for failure 1853 if ( ! $this->db_insert( $data['content_id'], $type, $period, $data['increment'] ) ) 1854 $success = false; 1855 } 1856 1857 return $success; 2227 $period_buckets = isset( $data['period_buckets'] ) && is_array( $data['period_buckets'] ) ? $data['period_buckets'] : ( isset( $data['visits'] ) && is_array( $data['visits'] ) ? $data['visits'] : [] ); 2228 2229 if ( empty( $period_buckets ) ) 2230 return false; 2231 2232 $visits_delta = isset( $data['visit_increment'] ) ? max( 0, (int) $data['visit_increment'] ) : 0; 2233 $visits_service = Post_Views_Counter()->visits instanceof Post_Views_Counter_Visits ? Post_Views_Counter()->visits : null; 2234 $availability = $visits_service ? $visits_service->get_visits_availability() : [ 'writable' => false, 'write_reason' => 'writer_unsupported' ]; 2235 2236 if ( isset( $availability['write_reason'] ) && $availability['write_reason'] === 'reset_in_progress' ) 2237 return false; 2238 2239 $visit_aware = ! empty( $availability['writable'] ); 2240 2241 if ( ! $visit_aware ) 2242 $visits_delta = 0; 2243 2244 $rows = []; 2245 2246 foreach ( $period_buckets as $type => $period ) { 2247 if ( (bool) apply_filters( 'pvc_skip_single_query', false, $data['content_id'], $type, $period, $data['increment'], 'post', $visits_delta ) ) 2248 continue; 2249 2250 $rows[] = [ 2251 'id' => (int) $data['content_id'], 2252 'type' => (int) $type, 2253 'period' => (string) $period, 2254 'count' => (int) $data['increment'], 2255 'visits' => $visits_delta 2256 ]; 2257 } 2258 2259 return empty( $rows ) || $this->write_period_rows( $rows, $visit_aware, true ); 2260 } 2261 2262 /** 2263 * Declare the complete Core visit-aware writer capability. 2264 * 2265 * @return bool 2266 */ 2267 public function supports_visit_writes() { 2268 return true; 2269 } 2270 2271 /** 2272 * Atomically add one complete set of period rows using prepared values. 2273 * A views-only fallback deliberately omits the visits column so a pending 2274 * or failed migration cannot interrupt existing view counting. 2275 * 2276 * The physical shape of the shared table is re-verified here rather than 2277 * trusted from the caller: `visit_aware` is downgraded when the Visits 2278 * service is absent or its content-column probe is inconclusive, and the 2279 * The extended `content` column is written only when it is known to exist. 2280 * 2281 * @param array $rows Period rows, each with id, type, period, count, visits. 2282 * @param bool $visit_aware Whether the verified writer may use visits. 2283 * 2284 * @return bool True on success, false when the database write failed. 2285 */ 2286 private function write_period_rows( $rows, $visit_aware, $use_write_fence = false ) { 2287 global $wpdb; 2288 2289 if ( empty( $rows ) ) 2290 return true; 2291 2292 $has_content = false; 2293 2294 if ( Post_Views_Counter()->visits instanceof Post_Views_Counter_Visits ) { 2295 $content_status = Post_Views_Counter()->visits->get_shared_content_column_status(); 2296 2297 if ( $content_status === null ) 2298 $visit_aware = false; 2299 else 2300 $has_content = $content_status; 2301 } else { 2302 $visit_aware = false; 2303 } 2304 2305 $write_fence = $use_write_fence && Post_Views_Counter()->visits instanceof Post_Views_Counter_Visits ? Post_Views_Counter()->visits->get_write_fence_token() : null; 2306 2307 if ( $use_write_fence && $write_fence === false ) 2308 return false; 2309 2310 $columns = [ '`id`', '`type`', '`period`', '`count`' ]; 2311 $placeholders = [ '%d', '%d', '%s', '%d' ]; 2312 2313 if ( $visit_aware ) { 2314 $columns[] = '`visits`'; 2315 $placeholders[] = '%d'; 2316 } 2317 2318 if ( $has_content ) { 2319 $columns[] = '`content`'; 2320 $placeholders[] = '%d'; 2321 } 2322 2323 $value_groups = []; 2324 $values = []; 2325 2326 foreach ( $rows as $row ) { 2327 $value_groups[] = '(' . implode( ', ', $placeholders ) . ')'; 2328 $values[] = (int) $row['id']; 2329 $values[] = (int) $row['type']; 2330 $values[] = (string) $row['period']; 2331 $values[] = (int) $row['count']; 2332 2333 if ( $visit_aware ) 2334 $values[] = max( 0, (int) $row['visits'] ); 2335 2336 if ( $has_content ) 2337 $values[] = 0; 2338 } 2339 2340 $target_table = '`' . $wpdb->prefix . 'post_views`'; 2341 $updates = [ '`count` = ' . $target_table . '.`count` + VALUES(`count`)' ]; 2342 2343 if ( $visit_aware ) 2344 $updates[] = '`visits` = ' . $target_table . '.`visits` + VALUES(`visits`)'; 2345 2346 $base_values = $values; 2347 $generation = is_array( $write_fence ) && isset( $write_fence['generation'] ) ? (int) $write_fence['generation'] : null; 2348 $attempts = $write_fence === null ? 1 : 3; 2349 $result = false; 2350 2351 for ( $attempt = 0; $attempt < $attempts; $attempt++ ) { 2352 $values = $base_values; 2353 2354 if ( is_array( $write_fence ) ) { 2355 $selects = []; 2356 2357 foreach ( $rows as $row_index => $row ) { 2358 $aliases = $row_index === 0 ? ' AS `id`, %d AS `type`, %s AS `period`, %d AS `count`' : ', %d, %s, %d'; 2359 $select = 'SELECT %d' . $aliases; 2360 $column_count = 4; 2361 2362 if ( $visit_aware ) { 2363 $select .= $row_index === 0 ? ', %d AS `visits`' : ', %d'; 2364 $column_count++; 2365 } 2366 2367 if ( $has_content ) { 2368 $select .= $row_index === 0 ? ', %d AS `content`' : ', %d'; 2369 $column_count++; 2370 } 2371 2372 $selects[] = $select; 2373 } 2374 2375 $predicate = ! empty( $write_fence['exists'] ) ? "EXISTS (SELECT 1 FROM `{$wpdb->options}` WHERE `option_name` = %s AND BINARY `option_value` = BINARY %s)" : "NOT EXISTS (SELECT 1 FROM `{$wpdb->options}` WHERE `option_name` = %s)"; 2376 $values[] = Post_Views_Counter_Visits::OPTION_NAME; 2377 2378 if ( ! empty( $write_fence['exists'] ) ) 2379 $values[] = $write_fence['raw']; 2380 2381 $sql = 'INSERT INTO ' . $target_table . ' (' . implode( ', ', $columns ) . ') SELECT * FROM (' . implode( ' UNION ALL ', $selects ) . ') AS `pvc_rows` WHERE ' . $predicate . ' ON DUPLICATE KEY UPDATE ' . implode( ', ', $updates ); 2382 } else 2383 $sql = 'INSERT INTO ' . $target_table . ' (' . implode( ', ', $columns ) . ') VALUES ' . implode( ', ', $value_groups ) . ' ON DUPLICATE KEY UPDATE ' . implode( ', ', $updates ); 2384 2385 $result = $wpdb->query( $wpdb->prepare( $sql, $values ) ); 2386 2387 if ( $result !== 0 || ! is_array( $write_fence ) ) 2388 break; 2389 2390 $next_fence = Post_Views_Counter()->visits->get_write_fence_token( true ); 2391 2392 if ( $next_fence === false || (int) $next_fence['generation'] !== $generation ) 2393 return false; 2394 2395 $write_fence = $next_fence; 2396 } 2397 2398 if ( $result === false || $result === 0 ) { 2399 error_log( 'Post Views Counter: shared counter write failed.' ); 2400 return false; 2401 } 2402 2403 if ( class_exists( 'Post_Views_Counter_Visits_Query' ) ) 2404 Post_Views_Counter_Visits_Query::invalidate_read_cache(); 2405 2406 return true; 1858 2407 } 1859 2408 … … 1877 2426 $data = apply_filters( 'pvc_delete_post_views_where_clause', $data, $post_id ); 1878 2427 1879 $wpdb->delete( $wpdb->prefix . 'post_views', $data['where'], $data['format'] ); 2428 $deleted = $wpdb->delete( $wpdb->prefix . 'post_views', $data['where'], $data['format'] ); 2429 2430 if ( $deleted > 0 && class_exists( 'Post_Views_Counter_Visits_Query' ) ) 2431 Post_Views_Counter_Visits_Query::invalidate_read_cache(); 1880 2432 } 1881 2433 … … 1936 2488 */ 1937 2489 public function flush_cache_to_db() { 1938 // get keys 2490 // The extended writer owns the four-part shared-row queue and its Visit 2491 // companion. Keep existing base update/email preflight callers compatible by delegating 2492 // through the active writer rather than parsing extended keys as base keys. 2493 if ( function_exists( 'Post_Views_Counter_Pro' ) ) { 2494 $pro = Post_Views_Counter_Pro(); 2495 2496 if ( is_object( $pro ) && isset( $pro->counter ) && is_object( $pro->counter ) && $pro->counter !== $this && method_exists( $pro->counter, 'flush_cache_to_db' ) ) { 2497 $result = $pro->counter->flush_cache_to_db( 'pvc' ); 2498 $this->last_cache_flush_status = method_exists( $pro->counter, 'get_cache_flush_status' ) ? $pro->counter->get_cache_flush_status() : ( $result ? 'completed' : 'failed' ); 2499 return $result; 2500 } 2501 } 2502 2503 $lock_token = $this->acquire_core_flush_lock(); 2504 2505 if ( $lock_token === false ) { 2506 $this->last_cache_flush_status = 'busy'; 2507 return false; 2508 } 2509 2510 try { 2511 $result = $this->flush_core_cache_owner( $lock_token ); 2512 $this->last_cache_flush_status = $result ? 'completed' : ( $this->core_flush_lock_owned( $lock_token ) ? 'failed' : 'ownership_lost' ); 2513 return $result; 2514 } finally { 2515 $this->release_core_flush_lock( $lock_token ); 2516 } 2517 } 2518 2519 /** 2520 * Return the outcome of this request's most recent cache flush attempt. 2521 * 2522 * @return string idle|busy|pending|failed|ownership_lost|completed 2523 */ 2524 public function get_cache_flush_status() { 2525 return $this->last_cache_flush_status; 2526 } 2527 2528 /** 2529 * Drain the legacy Core queue while the caller owns the drain lock. 2530 * 2531 * Database commit precedes cache acknowledgement. A crash can replay a 2532 * committed snapshot, but it cannot silently discard acknowledged work. 2533 * 2534 * @return bool 2535 */ 2536 private function flush_core_cache_owner( $lock_token ) { 2537 global $wpdb; 2538 1939 2539 $key_names = wp_cache_get( 'cached_key_names', 'pvc' ); 1940 1941 if ( ! $key_names ) 1942 $key_names = []; 1943 else { 1944 // create an array out of a string that's stored in the cache 1945 $key_names = explode( '|', $key_names ); 1946 } 1947 1948 // any data? 1949 if ( ! empty( $key_names ) ) { 1950 foreach ( $key_names as $key_name ) { 1951 // get values stored within the key name itself 1952 list( $id, $type, $period ) = explode( '.', $key_name ); 1953 1954 // get the cached count value 1955 $count = wp_cache_get( $key_name, 'pvc' ); 1956 1957 // store cached value in the database 1958 $this->db_prepare_insert( $id, $type, $period, $count ); 1959 1960 // clear the cache key we just flushed 1961 wp_cache_delete( $key_name, 'pvc' ); 2540 $key_names = is_string( $key_names ) ? array_filter( explode( '|', $key_names ), 'strlen' ) : (array) $key_names; 2541 $key_names = array_values( array_unique( array_filter( $key_names, 'strlen' ) ) ); 2542 2543 if ( empty( $key_names ) ) { 2544 wp_cache_delete( 'last-flush', 'pvc' ); 2545 return true; 2546 } 2547 2548 $batch_size = max( 1, absint( apply_filters( 'pvc_core_flush_batch_rows', 100 ) ) ); 2549 2550 foreach ( array_chunk( $key_names, $batch_size ) as $key_batch ) { 2551 $lock_ttl = $this->get_core_flush_lock_ttl(); 2552 2553 if ( ! $this->refresh_core_flush_lock( $lock_token, $lock_ttl ) ) 2554 return false; 2555 2556 $snapshots = []; 2557 $this->db_insert_values = []; 2558 2559 foreach ( $key_batch as $key_name ) { 2560 $key = $this->parse_core_queue_key( $key_name ); 2561 2562 if ( $key === null ) 2563 continue; 2564 2565 $count = (int) wp_cache_get( $key_name, 'pvc' ); 2566 2567 if ( $count <= 0 ) 2568 continue; 2569 2570 $snapshots[ $key_name ] = $count; 2571 2572 // Legacy three-part Core queue entries (id.type.period) carry a 2573 // View delta only; they have no Visit companion and predate the 2574 // Visits metric entirely. A Visit cannot be reconstructed from 2575 // them, so passing visit_increment = 0 here and committing with 2576 // visit_aware = false below is intentional: it preserves the 2577 // queued Views without inventing Visit data. 2578 if ( ! $this->db_prepare_insert( $key['id'], $key['type'], $key['period'], $count, 0, 'post' ) ) { 2579 $this->db_insert_values = []; 2580 return false; 2581 } 1962 2582 } 1963 2583 1964 // flush values to database 1965 $this->db_commit_insert(); 1966 1967 // delete the key holding the list 1968 wp_cache_delete( 'cached_key_names', 'pvc' ); 1969 } 1970 1971 // remove last flush 1972 wp_cache_delete( 'last-flush', 'pvc' ); 2584 // Renew immediately before acquiring the reset fence. The snapshot is 2585 // legacy generation 0 work, so only a generation read ordered by this 2586 // fence may authorize its database commit. 2587 if ( ! $this->refresh_core_flush_lock( $lock_token, $lock_ttl ) ) { 2588 $this->db_insert_values = []; 2589 return false; 2590 } 2591 2592 // Build every helper-dependent part of the Views-only upsert before the 2593 // measurement fence. Cache backends and extension callbacks are not safe 2594 // while MySQL permits this connection to use only two locked tables. 2595 $commit_sql = $this->prepare_core_legacy_insert_sql(); 2596 2597 if ( $commit_sql === false ) { 2598 $this->db_insert_values = []; 2599 return false; 2600 } 2601 2602 $fenced_renewal = $this->prepare_core_fenced_lock_renewal( $lock_token, $lock_ttl ); 2603 2604 if ( $fenced_renewal === false ) { 2605 $this->db_insert_values = []; 2606 return false; 2607 } 2608 2609 $fenced_generation_read = $this->prepare_core_fenced_generation_read(); 2610 2611 $visits = Post_Views_Counter()->visits; 2612 2613 if ( ! $visits instanceof Post_Views_Counter_Visits || ! $visits->begin_measurement_fence() ) { 2614 $this->db_insert_values = []; 2615 return false; 2616 } 2617 2618 $generation = false; 2619 $committed = false; 2620 $fence_result = [ 'unlocked' => false, 'flushed' => false ]; 2621 2622 try { 2623 // This fenced region permits only the prebuilt options UPDATE, an 2624 // uncached options SELECT, and the prebuilt post_views upsert. Do not 2625 // call WordPress/cache helpers here: extension callbacks may query an 2626 // unrelated table while LOCK TABLES is active. 2627 if ( ! $this->renew_core_flush_lock_fenced( $fenced_renewal ) ) { 2628 $this->db_insert_values = []; 2629 return false; 2630 } 2631 2632 $generation = $this->get_core_queue_generation_fenced( $fenced_generation_read ); 2633 2634 // A missing, malformed, or otherwise unusable durable state cannot 2635 // prove this legacy snapshot belongs before a reset. Fail closed and 2636 // leave the snapshot recoverable for a later retry. 2637 if ( $generation === false ) { 2638 $this->db_insert_values = []; 2639 return false; 2640 } 2641 2642 if ( $generation === 0 ) { 2643 if ( $commit_sql !== '' ) { 2644 $result = $wpdb->query( $commit_sql ); 2645 2646 if ( $result === false || $result === 0 ) 2647 return false; 2648 2649 $this->db_insert_values = []; 2650 $committed = true; 2651 } 2652 } else 2653 // Any supported Core scalar was published before the first reset. 2654 // Retire it without callbacks or writes; retaining its cache entry 2655 // makes a later retry prove the same generation before doing anything. 2656 $this->db_insert_values = []; 2657 } finally { 2658 $fence_result = $visits->end_measurement_fence(); 2659 } 2660 2661 // No cache acknowledgement or derived-cache retirement is valid until 2662 // the restrictive SQL fence has been confirmed released and its FIFO 2663 // publication work has completed. 2664 if ( empty( $fence_result['unlocked'] ) || empty( $fence_result['flushed'] ) ) 2665 return false; 2666 2667 // The legacy commit changes the Views numerator used by the Visit-derived 2668 // cache, so retire that cache only after the table fence is released. 2669 if ( $committed && class_exists( 'Post_Views_Counter_Visits_Query' ) ) 2670 Post_Views_Counter_Visits_Query::invalidate_read_cache(); 2671 2672 // The acknowledgement is outside the table fence, but must still prove 2673 // that this flusher owns the exact snapshot before changing cache state. 2674 if ( ! $this->refresh_core_flush_lock( $lock_token, $lock_ttl ) ) 2675 return false; 2676 2677 $completed = []; 2678 2679 foreach ( $snapshots as $key_name => $count ) { 2680 $remainder = wp_cache_decr( $key_name, $count, 'pvc' ); 2681 2682 if ( $remainder === false ) 2683 return false; 2684 2685 if ( (int) $remainder === 0 ) 2686 $completed[] = $key_name; 2687 } 2688 2689 if ( ! $this->cleanup_core_queue_membership( $completed ) ) 2690 return false; 2691 } 2692 2693 if ( wp_cache_delete( 'last-flush', 'pvc' ) === false && wp_cache_get( 'last-flush', 'pvc' ) !== false ) 2694 return false; 1973 2695 1974 2696 return true; … … 1976 2698 1977 2699 /** 1978 * Insert or update views count. 1979 * 1980 * @global object $wpdb 1981 * 1982 * @param int $id 1983 * @param int $type 1984 * @param string $period 1985 * @param int $count 1986 * 2700 * Build the legacy Views-only upsert before acquiring the measurement fence. 2701 * 2702 * @return string|false Prepared SQL, an empty string, or false on an unsafe shape. 2703 */ 2704 private function prepare_core_legacy_insert_sql() { 2705 global $wpdb; 2706 2707 if ( empty( $this->db_insert_values ) ) 2708 return ''; 2709 2710 $has_content = false; 2711 $visits = Post_Views_Counter()->visits; 2712 2713 if ( $visits instanceof Post_Views_Counter_Visits ) 2714 $has_content = $visits->get_shared_content_column_status() === true; 2715 2716 $columns = [ '`id`', '`type`', '`period`', '`count`' ]; 2717 $placeholders = [ '%d', '%d', '%s', '%d' ]; 2718 2719 if ( $has_content ) { 2720 $columns[] = '`content`'; 2721 $placeholders[] = '%d'; 2722 } 2723 2724 $value_groups = []; 2725 $values = []; 2726 2727 foreach ( $this->db_insert_values as $row ) { 2728 $value_groups[] = '(' . implode( ', ', $placeholders ) . ')'; 2729 $values[] = (int) $row['id']; 2730 $values[] = (int) $row['type']; 2731 $values[] = (string) $row['period']; 2732 $values[] = (int) $row['count']; 2733 2734 if ( $has_content ) 2735 $values[] = 0; 2736 } 2737 2738 $table = '`' . $wpdb->prefix . 'post_views`'; 2739 $sql = 'INSERT INTO ' . $table . ' (' . implode( ', ', $columns ) . ') VALUES ' . implode( ', ', $value_groups ) . ' ON DUPLICATE KEY UPDATE `count` = ' . $table . '.`count` + VALUES(`count`)'; 2740 2741 return $wpdb->prepare( $sql, $values ); 2742 } 2743 2744 /** 2745 * Capture an owner-checked lease replacement before the measurement fence. 2746 * 2747 * @param string $token Lock token. 2748 * @param int $ttl Lease duration in seconds. 2749 * @return string|false Prebuilt constrained options UPDATE or false. 2750 */ 2751 private function prepare_core_fenced_lock_renewal( $token, $ttl ) { 2752 global $wpdb; 2753 2754 $name = 'post_views_counter_core_flush_lock'; 2755 $raw = $wpdb->get_var( $wpdb->prepare( "SELECT `option_value` FROM `{$wpdb->options}` WHERE `option_name` = %s", $name ) ); 2756 $current = $raw === null ? false : maybe_unserialize( $raw ); 2757 2758 if ( ! is_array( $current ) || empty( $current['token'] ) || ! hash_equals( (string) $current['token'], (string) $token ) ) 2759 return false; 2760 2761 $replacement = [ 2762 'token' => $token, 2763 'expires_at' => max( time() + $ttl, (int) $current['expires_at'] + 1 ) 2764 ]; 2765 2766 return $wpdb->prepare( "UPDATE `{$wpdb->options}` SET `option_value` = %s WHERE `option_name` = %s AND BINARY `option_value` = BINARY %s", maybe_serialize( $replacement ), $name, $raw ); 2767 } 2768 2769 /** 2770 * Renew the Core lease while the measurement fence permits only options SQL. 2771 * 2772 * @param string $sql Prebuilt constrained UPDATE statement. 1987 2773 * @return bool 1988 2774 */ 1989 private function db_insert( $id, $type, $period, $count) {2775 private function renew_core_flush_lock_fenced( $sql ) { 1990 2776 global $wpdb; 1991 2777 1992 // skip single query? 1993 if ( (bool) apply_filters( 'pvc_skip_single_query', false, $id, $type, $period, $count, 'post' ) ) 1994 return true; // consider skipped as "successful" for this context 1995 1996 $result = $wpdb->query( $wpdb->prepare( 'INSERT INTO ' . $wpdb->prefix . 'post_views (`id`, `type`, `period`, `count`) VALUES (%d, %d, %s, %d) ON DUPLICATE KEY UPDATE count = count + %d', $id, $type, $period, $count, $count ) ); 1997 1998 // check for query failure 1999 if ( $result === false ) { 2000 // log the error for debugging 2001 error_log( sprintf( 'Post Views Counter: Failed to insert/update views for ID %d, type %d, period %s. MySQL error: %s', $id, $type, $period, $wpdb->last_error ) ); 2778 return $wpdb->query( $sql ) === 1; 2779 } 2780 2781 /** 2782 * Build the durable queue-generation SELECT before the measurement fence. 2783 * 2784 * @return string 2785 */ 2786 private function prepare_core_fenced_generation_read() { 2787 global $wpdb; 2788 2789 return $wpdb->prepare( "SELECT `option_value` FROM `{$wpdb->options}` WHERE `option_name` = %s", Post_Views_Counter_Visits::OPTION_NAME ); 2790 } 2791 2792 /** 2793 * Read the durable queue generation while the measurement fence is held. 2794 * 2795 * Missing state is the released generation-0 format. Existing state must be 2796 * the exact current durable shape required by get_queue_generation(). 2797 * 2798 * @param string $sql Prebuilt constrained options SELECT. 2799 * @return int|false 2800 */ 2801 private function get_core_queue_generation_fenced( $sql ) { 2802 global $wpdb; 2803 2804 $wpdb->last_error = ''; 2805 $raw = $wpdb->get_var( $sql ); 2806 2807 if ( $wpdb->last_error !== '' ) 2002 2808 return false; 2003 } 2004 2809 2810 if ( $raw === null ) 2811 return 0; 2812 2813 // Never instantiate serialized objects under the table fence. A poisoned 2814 // __wakeup()/autoload callback could issue SQL for a table MySQL has not 2815 // locked, so only a non-instantiating exact array decode is permitted here. 2816 if ( ! is_string( $raw ) || $raw === '' || substr( $raw, 0, 2 ) !== 'a:' || substr( $raw, -1 ) !== '}' ) 2817 return false; 2818 2819 set_error_handler( [ $this, 'suppress_core_fenced_decode_diagnostic' ] ); 2820 2821 try { 2822 $state = unserialize( $raw, [ 'allowed_classes' => false ] ); 2823 } finally { 2824 restore_error_handler(); 2825 } 2826 2827 $visits = Post_Views_Counter()->visits; 2828 2829 if ( ! $visits instanceof Post_Views_Counter_Visits || ! $visits->is_current_normal_state_raw( $state ) || serialize( $state ) !== $raw ) 2830 return false; 2831 2832 return $state['queue_generation']; 2833 } 2834 2835 /** 2836 * Contain unserialize diagnostics within the restricted fence without calling 2837 * a third-party error handler that could issue arbitrary SQL. 2838 * 2839 * @return bool 2840 */ 2841 private function suppress_core_fenced_decode_diagnostic() { 2005 2842 return true; 2006 2843 } 2007 2844 2008 2845 /** 2009 * Prepare bulk insert or update views count. 2010 * 2011 * @param int $id 2012 * @param int $type 2013 * @param string $period 2014 * @param int $count 2015 * 2846 * Parse one legacy base queue key without accepting the four-part extended 2847 * shape. 2848 * 2849 * @param mixed $key_name Cache key. 2850 * @return array|null 2851 */ 2852 private function parse_core_queue_key( $key_name ) { 2853 $raw_key_name = (string) $key_name; 2854 $key_name = sanitize_text_field( $raw_key_name ); 2855 2856 if ( $key_name !== $raw_key_name ) 2857 return null; 2858 2859 $parts = explode( '.', $key_name ); 2860 2861 if ( count( $parts ) !== 3 ) 2862 return null; 2863 2864 if ( ! ctype_digit( $parts[0] ) || ! ctype_digit( $parts[1] ) ) 2865 return null; 2866 2867 $id = (int) $parts[0]; 2868 $type = (int) $parts[1]; 2869 $period = sanitize_key( $parts[2] ); 2870 2871 if ( $period !== $parts[2] || $id < 1 || $type < 0 || $type > 4 || $period === '' ) 2872 return null; 2873 2874 if ( ! $this->is_valid_core_queue_period( (int) $type, $period ) ) 2875 return null; 2876 2877 return [ 'id' => $id, 'type' => (int) $type, 'period' => $period ]; 2878 } 2879 2880 /** 2881 * Validate the calendar identity encoded by a Core queue period. 2882 * 2883 * @param int $type Storage type. 2884 * @param string $period Storage period. 2885 * @return bool 2886 */ 2887 private function is_valid_core_queue_period( $type, $period ) { 2888 if ( $type === 4 ) 2889 return $period === 'total'; 2890 2891 if ( $type === 0 && preg_match( '/^\d{8}$/', $period ) ) 2892 return checkdate( (int) substr( $period, 4, 2 ), (int) substr( $period, 6, 2 ), (int) substr( $period, 0, 4 ) ); 2893 2894 if ( $type === 1 && preg_match( '/^(\d{4})(\d{2})$/', $period, $matches ) ) { 2895 $year = (int) $matches[1]; 2896 $week = (int) $matches[2]; 2897 2898 if ( $week < 1 || $week > 53 ) 2899 return false; 2900 2901 $date = ( new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) ) )->setISODate( $year, $week, 1 ); 2902 return $date->format( 'oW' ) === $period; 2903 } 2904 2905 if ( $type === 2 && preg_match( '/^(\d{4})(\d{2})$/', $period, $matches ) ) 2906 return (int) $matches[1] > 0 && (int) $matches[2] >= 1 && (int) $matches[2] <= 12; 2907 2908 return $type === 3 && preg_match( '/^\d{4}$/', $period ) && (int) $period > 0; 2909 } 2910 2911 /** 2912 * Remove completed Core scalars and only their membership entries. 2913 * 2914 * @param array $completed Completed keys. 2915 * @return bool 2916 */ 2917 private function cleanup_core_queue_membership( $completed ) { 2918 if ( empty( $completed ) ) 2919 return true; 2920 2921 $live = wp_cache_get( 'cached_key_names', 'pvc' ); 2922 $live = is_string( $live ) ? array_filter( explode( '|', $live ), 'strlen' ) : (array) $live; 2923 $remaining = []; 2924 2925 foreach ( $live as $key_name ) { 2926 if ( in_array( $key_name, $completed, true ) && (int) wp_cache_get( $key_name, 'pvc' ) === 0 ) { 2927 if ( ! wp_cache_delete( $key_name, 'pvc' ) && wp_cache_get( $key_name, 'pvc' ) !== false ) 2928 return false; 2929 2930 continue; 2931 } 2932 2933 $remaining[] = $key_name; 2934 } 2935 2936 $remaining = array_values( array_unique( array_filter( $remaining, 'strlen' ) ) ); 2937 2938 if ( empty( $remaining ) ) 2939 return wp_cache_delete( 'cached_key_names', 'pvc' ) || wp_cache_get( 'cached_key_names', 'pvc' ) === false; 2940 2941 return (bool) wp_cache_set( 'cached_key_names', implode( '|', $remaining ), 'pvc' ); 2942 } 2943 2944 /** 2945 * Acquire the Core drain lock with token-conditioned stale takeover. 2946 * 2947 * @return string|false 2948 */ 2949 private function acquire_core_flush_lock() { 2950 $name = 'post_views_counter_core_flush_lock'; 2951 $token = wp_generate_uuid4(); 2952 $lock = [ 'token' => $token, 'expires_at' => time() + max( 30, absint( apply_filters( 'pvc_core_flush_lock_ttl', 300 ) ) ) ]; 2953 2954 if ( add_option( $name, $lock, '', false ) ) 2955 return $token; 2956 2957 $current = get_option( $name, [] ); 2958 2959 if ( is_array( $current ) && ! empty( $current['expires_at'] ) && (int) $current['expires_at'] > time() ) 2960 return false; 2961 2962 return $this->replace_core_lock_if_unchanged( $name, $current, $lock ) ? $token : false; 2963 } 2964 2965 /** 2966 * Refresh the Core drain lease only while the token still owns it. 2967 * 2968 * @param string $token Lock token. 2969 * @param int|null $ttl Optional pre-evaluated lease duration. 2970 * @return bool 2971 */ 2972 private function refresh_core_flush_lock( $token, $ttl = null ) { 2973 $name = 'post_views_counter_core_flush_lock'; 2974 $current = get_option( $name, [] ); 2975 2976 if ( ! is_array( $current ) || empty( $current['token'] ) || ! hash_equals( (string) $current['token'], (string) $token ) ) 2977 return false; 2978 2979 $replacement = [ 2980 'token' => $token, 2981 'expires_at' => max( 2982 time() + ( $ttl === null ? $this->get_core_flush_lock_ttl() : $ttl ), 2983 (int) $current['expires_at'] + 1 2984 ) 2985 ]; 2986 2987 return $this->replace_core_lock_if_unchanged( $name, $current, $replacement ); 2988 } 2989 2990 /** 2991 * Resolve the Core drain lease duration before entering a table fence. 2992 * 2993 * @return int 2994 */ 2995 private function get_core_flush_lock_ttl() { 2996 return max( 30, absint( apply_filters( 'pvc_core_flush_lock_ttl', 300 ) ) ); 2997 } 2998 2999 /** 3000 * Check current Core drain ownership. 3001 * 3002 * @param string $token Lock token. 3003 * @return bool 3004 */ 3005 private function core_flush_lock_owned( $token ) { 3006 $current = get_option( 'post_views_counter_core_flush_lock', [] ); 3007 3008 return is_array( $current ) && ! empty( $current['token'] ) && hash_equals( (string) $current['token'], (string) $token ); 3009 } 3010 3011 /** 3012 * Release the Core drain lock only while still its owner. 3013 * 3014 * @param string $token Owner token. 2016 3015 * @return void 2017 3016 */ 2018 private function db_prepare_insert( $id, $type, $period, $count = 1 ) { 2019 // cast count 3017 private function release_core_flush_lock( $token ) { 3018 global $wpdb; 3019 3020 $name = 'post_views_counter_core_flush_lock'; 3021 $current = get_option( $name, [] ); 3022 3023 if ( ! is_array( $current ) || empty( $current['token'] ) || ! hash_equals( (string) $current['token'], (string) $token ) ) 3024 return; 3025 3026 $result = $wpdb->query( $wpdb->prepare( "DELETE FROM `{$wpdb->options}` WHERE `option_name` = %s AND `option_value` = %s", $name, maybe_serialize( $current ) ) ); 3027 3028 if ( $result === 1 ) 3029 wp_cache_delete( $name, 'options' ); 3030 } 3031 3032 /** 3033 * Replace an expired Core drain lock without delete-then-add takeover. 3034 * 3035 * @param string $name Option name. 3036 * @param mixed $expected Expected lock. 3037 * @param array $replacement Replacement lock. 3038 * @return bool 3039 */ 3040 private function replace_core_lock_if_unchanged( $name, $expected, $replacement ) { 3041 global $wpdb; 3042 3043 $result = $wpdb->query( $wpdb->prepare( "UPDATE `{$wpdb->options}` SET `option_value` = %s WHERE `option_name` = %s AND `option_value` = %s", maybe_serialize( $replacement ), $name, maybe_serialize( $expected ) ) ); 3044 3045 if ( $result === 1 ) 3046 wp_cache_delete( $name, 'options' ); 3047 3048 return $result === 1; 3049 } 3050 3051 /** 3052 * Buffer one period row for the next multi-row commit. 3053 * 3054 * Rows are accumulated in `$db_insert_values` and written by 3055 * `db_commit_insert()`. A skipped row is reported as success because the 3056 * caller asked for it to be omitted, not because a write failed. 3057 * 3058 * @param int $id Content ID. 3059 * @param int $type Period type (0-4). 3060 * @param string $period Period bucket value. 3061 * @param int $count View increment for this row. 3062 * @param int $visit_increment Visit increment for this row; 0 for Views-only. 3063 * @param string $content_type Content type passed to `pvc_skip_single_query`. 3064 * 3065 * @return bool True when the row was buffered or deliberately skipped. 3066 */ 3067 private function db_prepare_insert( $id, $type, $period, $count = 1, $visit_increment = 0, $content_type = 'post' ) { 2020 3068 $count = (int) $count; 2021 2022 if ( ! $count ) 2023 $count = 1; 2024 2025 // any queries? 2026 if ( ! empty( $this->db_insert_values ) ) 2027 $this->db_insert_values .= ', '; 2028 2029 // append insert queries 2030 $this->db_insert_values .= sprintf( '(%d, %d, "%s", %d)', $id, $type, $period, $count ); 2031 2032 if ( strlen( $this->db_insert_values ) > 25000 ) 2033 $this->db_commit_insert(); 2034 } 2035 2036 /** 2037 * Insert accumulated values to database. 2038 * 2039 * @global object $wpdb 2040 * 2041 * @return int|bool 2042 */ 2043 private function db_commit_insert() { 2044 global $wpdb; 2045 3069 $visit_increment = max( 0, (int) $visit_increment ); 3070 3071 if ( (bool) apply_filters( 'pvc_skip_single_query', false, $id, $type, $period, $count, $content_type, $visit_increment ) ) 3072 return true; 3073 3074 $this->db_insert_values[] = [ 3075 'id' => (int) $id, 3076 'type' => (int) $type, 3077 'period' => (string) $period, 3078 'count' => $count, 3079 'visits' => $visit_increment 3080 ]; 3081 3082 return true; 3083 } 3084 3085 /** 3086 * Write every buffered period row in one prepared multi-row upsert. 3087 * 3088 * @param bool $visit_aware Whether the verified writer may use the `visits` 3089 * column. Callers that cannot reconstruct Visits 3090 * must pass false so the column is left untouched. 3091 * 3092 * @return bool True on success, false when there was nothing buffered or the 3093 * write failed. The buffer is only cleared on success. 3094 */ 3095 private function db_commit_insert( $visit_aware = false ) { 2046 3096 if ( empty( $this->db_insert_values ) ) 2047 3097 return false; 2048 3098 2049 $result = $wpdb->query( 2050 "INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count) 2051 VALUES " . $this->db_insert_values . " 2052 ON DUPLICATE KEY UPDATE count = count + VALUES(count)" 2053 ); 2054 2055 $this->db_insert_values = ''; 3099 $result = $this->write_period_rows( $this->db_insert_values, $visit_aware ); 3100 3101 if ( $result !== false ) 3102 $this->db_insert_values = []; 2056 3103 2057 3104 return $result; … … 2355 3402 'storage_data_all' => [ 2356 3403 'default' => '' 3404 ], 3405 'storage_capable' => [ 3406 'sanitize_callback' => 'rest_sanitize_boolean' 2357 3407 ] 2358 3408 ] ) … … 2370 3420 'args' => apply_filters( 'pvc_rest_api_get_post_views_args', [ 2371 3421 'id' => [ 2372 'default' => 0, 2373 'sanitize_callback' => [ $this, 'validate_rest_api_data' ] 2374 ] 3422 'default' => 0 3423 ], 3424 'metric' => [], 3425 'period' => [ 'default' => 'total' ], 3426 'type' => [ 'default' => 'post' ] 2375 3427 ] ) 2376 3428 ] … … 2386 3438 */ 2387 3439 public function get_post_views_rest_api( $request ) { 2388 return pvc_get_post_views( $request->get_param( 'id' ) ); 3440 $raw_metric = $request->get_param( 'metric' ); 3441 $raw_id = $request->get_param( 'id' ); 3442 3443 if ( ! is_scalar( $raw_id ) || ! preg_match( '/^[1-9]\d*(,[1-9]\d*)*$/', (string) $raw_id ) ) 3444 return new WP_Error( 'pvc_invalid_metric', __( 'The requested PVC metric is not supported.', 'post-views-counter' ), [ 'status' => 400 ] ); 3445 3446 $ids = array_values( array_filter( array_unique( array_map( 'absint', explode( ',', (string) $raw_id ) ) ) ) ); 3447 3448 // Preserve the exact legacy scalar response when named metric mode is absent. 3449 if ( $raw_metric === null ) 3450 return pvc_get_post_views( $ids ); 3451 3452 if ( ! is_scalar( $raw_metric ) ) 3453 return new WP_Error( 'pvc_invalid_metric', __( 'The requested PVC metric is not supported.', 'post-views-counter' ), [ 'status' => 400 ] ); 3454 3455 $metric = (string) $raw_metric; 3456 3457 if ( count( $ids ) > self::REST_MAX_TARGETS ) 3458 return new WP_Error( 'pvc_too_many_targets', __( 'Too many PVC metric targets were requested.', 'post-views-counter' ), [ 'status' => 400 ] ); 3459 $raw_period = $request->get_param( 'period' ); 3460 $period = is_scalar( $raw_period ) ? (string) $raw_period : ''; 3461 $raw_type = $request->get_param( 'type' ); 3462 $type = is_scalar( $raw_type ) ? (string) $raw_type : ''; 3463 3464 // Visits Cleanup Addendum -- 2026-09-26 (O2): the named read is Views-only 3465 if ( $metric !== 'views' || $type !== 'post' || ! preg_match( '/^[a-z0-9_-]+$/', $period ) ) 3466 return new WP_Error( 'pvc_invalid_metric', __( 'The requested PVC metric is not supported.', 'post-views-counter' ), [ 'status' => 400 ] ); 3467 3468 $normalized = function_exists( 'pvc_normalize_views_period' ) ? pvc_normalize_views_period( $period ) : null; 3469 3470 if ( $normalized === null ) 3471 $availability = [ 'readable' => false, 'read_reason' => 'invalid_period' ]; 3472 else { 3473 $content_status = isset( Post_Views_Counter()->visits ) ? Post_Views_Counter()->visits->get_shared_content_column_status() : false; 3474 $availability = $content_status === null ? [ 'readable' => false, 'read_reason' => 'schema_probe_failed' ] : [ 'readable' => true, 'read_reason' => 'ready' ]; 3475 } 3476 3477 $raw_values = []; 3478 3479 if ( ! empty( $availability['readable'] ) ) 3480 $raw_values = $this->get_named_post_view_values( $ids, $period, $normalized ); 3481 3482 $values = []; 3483 $formatted = []; 3484 $display_options = Post_Views_Counter()->options['display']; 3485 3486 foreach ( $ids as $id ) { 3487 $key = 'post:' . $id . ':' . $period; 3488 $value = empty( $availability['readable'] ) ? null : ( isset( $raw_values[$id] ) ? $raw_values[$id] : 0 ); 3489 $values[$key] = $value; 3490 3491 // An unreadable View is not a stored zero, so it never reaches numeric 3492 // formatting; it renders the unavailable dash instead. 3493 $display_value = $value === null ? '—' : ( ! empty( $display_options['use_format'] ) ? number_format_i18n( $value ) : (string) $value ); 3494 $filtered_value = apply_filters( 'pvc_post_views_number_format', $display_value, $id ); 3495 3496 $filtered_value = is_scalar( $filtered_value ) ? (string) $filtered_value : $display_value; 3497 $formatted[$key] = html_entity_decode( wp_strip_all_tags( $filtered_value ), ENT_QUOTES, 'UTF-8' ); 3498 } 3499 3500 // Anonymous dynamic payloads expose only the stable raw-read result. They 3501 // never expose schema internals or other internal state metadata. 3502 $public_availability = [ 3503 'readable' => ! empty( $availability['readable'] ), 3504 'reason' => isset( $availability['read_reason'] ) ? sanitize_key( $availability['read_reason'] ) : 'unavailable' 3505 ]; 3506 3507 return [ 3508 'metric' => $metric, 3509 'type' => $type, 3510 'period' => $period, 3511 'values' => $values, 3512 'formatted' => $formatted, 3513 'availability' => $public_availability 3514 ]; 3515 } 3516 3517 /** 3518 * Read named post Views in one grouped query while preserving value filters. 3519 * 3520 * @param int[] $ids Post IDs. 3521 * @param string $period Requested period. 3522 * @param array $normalized Canonical period. 3523 * @return int[] Values keyed by post ID. 3524 */ 3525 private function get_named_post_view_values( $ids, $period, $normalized ) { 3526 if ( $this->has_custom_post_views_period_filter() ) { 3527 $values = []; 3528 3529 foreach ( $ids as $id ) 3530 $values[$id] = pvc_get_post_views( $id, $period ); 3531 3532 return $values; 3533 } 3534 3535 global $wpdb; 3536 $params = $ids; 3537 $where = [ 'id IN (' . implode( ', ', array_fill( 0, count( $ids ), '%d' ) ) . ')', 'type = %d' ]; 3538 $params[] = (int) $normalized['type']; 3539 3540 if ( (int) $normalized['type'] === 4 ) { 3541 $where[] = 'period = %s'; 3542 $params[] = 'total'; 3543 } elseif ( $normalized['period_from'] === $normalized['period_to'] ) { 3544 $where[] = 'CAST(period AS SIGNED) = %d'; 3545 $params[] = (int) $normalized['period_from']; 3546 } else { 3547 $where[] = 'CAST(period AS SIGNED) BETWEEN %d AND %d'; 3548 $params[] = (int) $normalized['period_from']; 3549 $params[] = (int) $normalized['period_to']; 3550 } 3551 3552 $content_status = isset( Post_Views_Counter()->visits ) ? Post_Views_Counter()->visits->get_shared_content_column_status() : false; 3553 3554 if ( $content_status === null ) 3555 return []; 3556 3557 if ( $content_status ) 3558 $where[] = 'content = 0'; 3559 3560 $sql = $wpdb->prepare( 'SELECT id, SUM(count) AS views FROM `' . $wpdb->prefix . 'post_views` WHERE ' . implode( ' AND ', $where ) . ' GROUP BY id', $params ); 3561 $cache_key = md5( $sql ); 3562 $rows = wp_cache_get( $cache_key, 'pvc-get_post_views' ); 3563 3564 if ( $rows === false ) { 3565 $rows = $wpdb->get_results( $sql, ARRAY_A ); 3566 $rows = is_array( $rows ) ? $rows : []; 3567 wp_cache_add( $cache_key, $rows, 'pvc-get_post_views', absint( apply_filters( 'pvc_object_cache_expire', 300 ) ) ); 3568 } 3569 3570 $values = array_fill_keys( $ids, 0 ); 3571 3572 foreach ( $rows as $row ) { 3573 $id = isset( $row['id'] ) ? absint( $row['id'] ) : 0; 3574 3575 if ( array_key_exists( $id, $values ) ) 3576 $values[$id] = isset( $row['views'] ) ? (int) $row['views'] : 0; 3577 } 3578 3579 foreach ( $values as $id => $value ) 3580 $values[$id] = (int) apply_filters( 'pvc_get_post_views', $value, $id, $period, [] ); 3581 3582 return $values; 3583 } 3584 3585 /** 3586 * Check for period filters beyond the canonical post discriminator. 3587 * 3588 * @return bool 3589 */ 3590 private function has_custom_post_views_period_filter() { 3591 global $wp_filter; 3592 3593 if ( empty( $wp_filter['pvc_get_post_views_period_where'] ) || ! isset( $wp_filter['pvc_get_post_views_period_where']->callbacks ) ) 3594 return false; 3595 3596 foreach ( $wp_filter['pvc_get_post_views_period_where']->callbacks as $callbacks ) { 3597 foreach ( $callbacks as $callback ) { 3598 if ( ! isset( $callback['function'] ) || $callback['function'] !== 'pvc_get_post_views_period_where' ) 3599 return true; 3600 } 3601 } 3602 3603 return false; 2389 3604 } 2390 3605 -
post-views-counter/tags/1.8.0/includes/class-cron.php
r3556892 r3734102 30 30 * @global object $wpdb 31 31 * 32 * @return void32 * @return bool 33 33 */ 34 34 public function reset_counts() { 35 35 global $wpdb; 36 36 37 $days = $this->get_reset_interval_days(); 38 39 // a zero or invalid interval keeps data regardless of age 40 if ( $days === 0 ) 41 return true; 42 43 // default where clause 44 $where = [ 'type = 0', 'CAST( period AS SIGNED ) < CAST( ' . date( 'Ymd', strtotime( '-' . $days . ' days' ) ) . ' AS SIGNED)' ]; 45 46 // update where clause 47 $where = apply_filters( 'pvc_reset_counts_where_clause', $where ); 48 // Keep the established selection predicate. Retention deletes stored rows 49 // only; it never changes raw-read or derived eligibility boundaries. 50 $result = $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'post_views WHERE ' . implode( ' AND ', $where ) ); 51 52 if ( $result === false ) 53 return false; 54 55 if ( class_exists( 'Post_Views_Counter_Visits_Query' ) ) 56 Post_Views_Counter_Visits_Query::invalidate_read_cache(); 57 58 return true; 59 } 60 61 /** 62 * Get the cleanup interval in days. 63 * 64 * @return int Days, or 0 when the interval is zero or invalid 65 */ 66 private function get_reset_interval_days() { 37 67 $counter = [ 38 68 'days' => 1, … … 45 75 $pvc = Post_Views_Counter(); 46 76 47 // default where clause 48 $where = [ 'type = 0', 'CAST( period AS SIGNED ) < CAST( ' . date( 'Ymd', strtotime( '-' . ( (int) ( $counter[$pvc->options['general']['reset_counts']['type']] * $pvc->options['general']['reset_counts']['number'] ) ) . ' days' ) ) . ' AS SIGNED)' ]; 77 $interval = isset( $pvc->options['general']['reset_counts'] ) && is_array( $pvc->options['general']['reset_counts'] ) ? $pvc->options['general']['reset_counts'] : []; 78 $type = isset( $interval['type'] ) && is_string( $interval['type'] ) ? $interval['type'] : ''; 79 $number = isset( $interval['number'] ) && is_numeric( $interval['number'] ) ? (int) $interval['number'] : 0; 49 80 50 // update where clause51 $where = apply_filters( 'pvc_reset_counts_where_clause', $where );81 if ( ! isset( $counter[$type] ) || $number < 1 || $number > 999999 ) 82 return 0; 52 83 53 // delete views 54 $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'post_views WHERE ' . implode( ' AND ', $where ) ); 84 return $counter[$type] * $number; 55 85 } 56 86 … … 90 120 $pvc = Post_Views_Counter(); 91 121 92 // set wp cron task 93 if ( $pvc->options['general']['cron_run'] ) {122 // set wp cron task, only for a valid positive interval 123 if ( $pvc->options['general']['cron_run'] && $this->get_reset_interval_days() > 0 ) { 94 124 // not set or need to be updated? 95 125 if ( ! wp_next_scheduled( 'pvc_reset_counts' ) || $pvc->options['general']['cron_update'] ) { -
post-views-counter/tags/1.8.0/includes/class-dashboard.php
r3537950 r3734102 11 11 class Post_Views_Counter_Dashboard { 12 12 13 /** 14 * The insight notice list this Core renders. 15 * 16 * A paired chart item carries a box that the dashboard script fills from a 17 * widget payload's `insight_notices` on every successful load, and 18 * Post_Views_Counter_Dashboard_Comparison is available. An extension 19 * detects it on the loaded dashboard object's class, never by version. 20 * 21 * @since 1.7.16 22 * 23 * @var int 24 */ 25 const NOTICES_FORMAT = 1; 26 27 /** 28 * Fewest Views on each side of the comparison notice. This Core constant 29 * is separate from the Traffic Signal floor. 30 * 31 * @internal 32 * 33 * @since 1.7.16 34 * 35 * @var int 36 */ 37 const FREE_NOTICE_MIN_VIEWS = 10; 38 13 39 private $widget_items = []; 40 41 /** 42 * Current time of the period comparison; null is now. Set only by tests. 43 * 44 * @var DateTimeInterface|null 45 */ 46 private $now = null; 14 47 15 48 /** … … 21 54 // actions 22 55 add_action( 'admin_init', [ $this, 'init_admin_dashboard' ] ); 56 add_action( 'pvc_dashboard_widget_content_top', [ $this, 'render_widget_headline' ] ); 23 57 } 24 58 … … 76 110 77 111 // scripts 78 wp_enqueue_script( 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/js/admin-dashboard.js', [ 'jquery', 'pvc-chartjs' ], $pvc->defaults['version'], true );112 wp_enqueue_script( 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/js/admin-dashboard.js', [ 'jquery', 'pvc-chartjs', 'pvc-metric-toggle' ], $pvc->defaults['version'], true ); 79 113 80 114 // prepare script data … … 106 140 'title' => __( 'Post Views', 'post-views-counter' ), 107 141 'description' => __( 'Displays a chart of most viewed post types.', 'post-views-counter' ), 108 'content' => '<canvas id="pvc-post-views-chart" height="' . (int) $this->calculate_canvas_size( Post_Views_Counter()->options['general']['post_types_count'] ) . '"></canvas>', 142 // The first-party chart no longer derives a canvas height from 143 // the legend size. It lives in a fixed CSS wrapper so the plotted 144 // graph is the same height in every metric mode while the 145 // controls and the dataset legend grow the widget around it. 146 'content' => '<div class="pvc-chart-wrapper"><canvas id="pvc-post-views-chart"></canvas></div>', 147 'metrics' => true, 109 148 'position' => 2 110 149 ], … … 228 267 ]; 229 268 269 // Only first-party paired widgets opt in. A widget added through 270 // pvc_dashboard_widget_items by an older extension or a third party never 271 // gets the controls, so it keeps its exact current markup. 272 $has_metrics = ! empty( $item['metrics'] ); 273 230 274 ob_start(); ?> 231 275 … … 239 283 </div> 240 284 <div class="pvc-accordion-content"> 241 <div class="pvc-dashboard-container loading ">285 <div class="pvc-dashboard-container loading<?php echo $has_metrics ? ' pvc-dashboard-container-chart' : ''; ?>"> 242 286 <div class="pvc-dashboard-content-top"> 243 287 <?php do_action( 'pvc_dashboard_widget_content_top', $item['id'] ); ?> 244 288 </div> 289 <?php if ( $has_metrics ) : ?> 290 <div class="pvc-dashboard-metric-controls"> 291 <div class="pvc-dashboard-metrics" data-pvc-widget="<?php echo esc_attr( $item['id'] ); ?>" role="group" aria-label="<?php esc_attr_e( 'Chart metrics', 'post-views-counter' ); ?>"></div> 292 <p class="pvc-dashboard-visits-unavailable" id="pvc-<?php echo esc_attr( $item['id'] ); ?>-visits-unavailable" hidden></p> 293 </div> 294 <?php endif; ?> 245 295 <div class="pvc-data-container"> 246 296 <?php echo wp_kses( $item['content'], $allowed_html ); ?> … … 248 298 <span class="spinner"></span> 249 299 </div> 300 <?php if ( $has_metrics ) : ?> 301 <div class="pvc-dashboard-legend" data-pvc-widget="<?php echo esc_attr( $item['id'] ); ?>" role="group" aria-label="<?php esc_attr_e( 'Chart datasets', 'post-views-counter' ); ?>"></div> 302 <div class="pvc-widget-insights" id="pvc-<?php echo esc_attr( $item['id'] ); ?>-widget-insights" aria-live="polite" hidden></div> 303 <?php endif; ?> 304 <?php $this->render_widget_insights( $item['id'] ); ?> 250 305 <div class="pvc-dashboard-content-bottom"> 251 306 <div class="pvc-date-nav pvc-months"> … … 267 322 268 323 /** 324 * Render monthly period controls and the chart's Views headline when no extension owns the header. 325 * 326 * @param string $widget_id Widget item ID. 327 * @return void 328 */ 329 public function render_widget_headline( $widget_id ) { 330 if ( ! in_array( $widget_id, [ 'post-views', 'post-most-viewed' ], true ) || class_exists( 'Post_Views_Counter_Pro' ) ) 331 return; 332 ?> 333 <div class="pvc-dashboard-headline"> 334 <?php if ( $widget_id === 'post-views' ) : ?> 335 <div class="pvc-summary"><span class="pvc-data-count" aria-live="polite"></span></div> 336 <?php endif; ?> 337 <div class="pvc-date-select button-group <?php echo esc_attr( $widget_id ); ?>" role="group" aria-label="<?php echo esc_attr( $widget_id === 'post-views' ? __( 'Chart period', 'post-views-counter' ) : __( 'Views Period', 'post-views-counter' ) ); ?>"> 338 <button type="button" class="button button-small button-secondary" data-datenav="yearly" title="<?php esc_attr_e( 'Yearly', 'post-views-counter' ); ?>" aria-label="<?php esc_attr_e( 'Yearly', 'post-views-counter' ); ?>" aria-pressed="false" disabled><span>Y</span></button> 339 <button type="button" class="button button-small button-primary" data-datenav="monthly" title="<?php esc_attr_e( 'Monthly', 'post-views-counter' ); ?>" aria-label="<?php esc_attr_e( 'Monthly', 'post-views-counter' ); ?>" aria-pressed="true">M</button> 340 <button type="button" class="button button-small button-secondary" data-datenav="weekly" title="<?php esc_attr_e( 'Weekly', 'post-views-counter' ); ?>" aria-label="<?php esc_attr_e( 'Weekly', 'post-views-counter' ); ?>" aria-pressed="false" disabled><span>W</span></button> 341 </div> 342 </div> 343 <?php 344 } 345 346 /** 347 * Fire the insights slot of a dashboard widget item. 348 * 349 * A slot between the chart legend and the date navigation, fired for every 350 * item. Core prints no markup of its own there; an extension decides by the 351 * widget ID whether anything belongs to it. 352 * 353 * @since 1.7.16 354 * 355 * @param string $widget_id Widget item ID. 356 * @return void 357 */ 358 public function render_widget_insights( $widget_id ) { 359 do_action( 'pvc_dashboard_widget_content_insights', $widget_id ); 360 } 361 362 /** 363 * Get the allow-listed metric display modes. 364 * 365 * @return array 366 */ 367 public function get_metric_modes() { 368 return [ 'both', 'views', 'visits' ]; 369 } 370 371 /** 372 * Get the stored metric display mode of one widget. 373 * 374 * This is the preferred mode, not the effective one. A temporary Visits 375 * outage never rewrites it. 376 * 377 * @param string $widget_id Dashboard widget identifier. 378 * @param int $user_id User ID. 379 * @return string 380 */ 381 public function get_widget_metric_mode( $widget_id, $user_id = 0 ) { 382 $modes = $this->get_dashboard_user_options( $user_id, 'metrics' ); 383 $mode = isset( $modes[$widget_id] ) ? $modes[$widget_id] : ''; 384 385 // both metrics are on for a user with no stored preference 386 return in_array( $mode, $this->get_metric_modes(), true ) ? $mode : 'both'; 387 } 388 389 /** 390 * Get the readable state of the dashboard Visit series. 391 * 392 * Raw dashboard buckets ignore derived_since entirely: a readable slot with 393 * no stored row is zero, and only an unreadable series is withheld. 394 * 395 * @return array 396 */ 397 public function get_dashboard_visits_availability() { 398 $availability = isset( Post_Views_Counter()->visits ) ? Post_Views_Counter()->visits->get_visits_availability() : [ 'readable' => false, 'read_reason' => 'schema_failed' ]; 399 $readable = ! empty( $availability['readable'] ); 400 401 return [ 402 'readable' => $readable, 403 'reason' => $readable ? 'ready' : ( isset( $availability['read_reason'] ) ? $availability['read_reason'] : 'read_failed' ) 404 ]; 405 } 406 407 /** 408 * Build the ordered chart buckets of one dashboard views_query. 409 * 410 * The order and the grain deliberately mirror what pvc_get_views() builds 411 * for the same query with `date=>views`, so a Visit series lines up with the 412 * Views series it is paired with. Weekly and monthly charts use daily 413 * buckets; a year uses monthly buckets. 414 * 415 * @param array $views_query Dashboard views query. 416 * @return array|null Storage type and ordered period keys, or null. 417 */ 418 public function get_chart_buckets( $views_query ) { 419 $views_query = is_array( $views_query ) ? $views_query : []; 420 421 $year = ! empty( $views_query['year'] ) ? str_pad( (int) $views_query['year'], 4, '0', STR_PAD_LEFT ) : ''; 422 $month = ! empty( $views_query['month'] ) ? str_pad( (int) $views_query['month'], 2, '0', STR_PAD_LEFT ) : ''; 423 $week = ! empty( $views_query['week'] ) ? str_pad( (int) $views_query['week'], 2, '0', STR_PAD_LEFT ) : ''; 424 $day = ! empty( $views_query['day'] ) ? str_pad( (int) $views_query['day'], 2, '0', STR_PAD_LEFT ) : ''; 425 426 if ( $year === '' ) 427 return null; 428 429 $periods = []; 430 431 // year and week: the seven days of that ISO week 432 if ( $week !== '' ) { 433 $date = new DateTime( $year . 'W' . $week ); 434 435 for ( $i = 1; $i <= 7; $i++ ) { 436 $periods[] = $date->format( 'Ymd' ); 437 $date->modify( '+1 days' ); 438 } 439 440 return [ 'type' => 0, 'periods' => $periods ]; 441 } 442 443 if ( $month !== '' ) { 444 // year, month and day: one daily bucket 445 if ( $day !== '' ) 446 return [ 'type' => 0, 'periods' => [ $year . $month . $day ] ]; 447 448 // year and month: every day of that month 449 $date = new DateTime( $year . '-' . $month . '-01' ); 450 $last = (int) $date->format( 't' ); 451 452 for ( $i = 1; $i <= $last; $i++ ) { 453 $periods[] = $year . $month . str_pad( $i, 2, '0', STR_PAD_LEFT ); 454 } 455 456 return [ 'type' => 0, 'periods' => $periods ]; 457 } 458 459 // year: twelve monthly buckets 460 for ( $i = 1; $i <= 12; $i++ ) { 461 $periods[] = $year . str_pad( $i, 2, '0', STR_PAD_LEFT ); 462 } 463 464 return [ 'type' => 2, 'periods' => $periods ]; 465 } 466 467 /** 468 * Key a paired chart's Views read by the Visits read generation. 469 * 470 * Views reads are cached by their SQL for the cache lifetime, while the 471 * Visit series drawn beside them is keyed by the Visits read generation, 472 * which every committed write, cleanup or reset advances. A trailing SQL 473 * comment carrying that key gives the chart's Views the same freshness 474 * boundary, so both series retire together. Nothing is flushed, and every 475 * other Views read keeps its key. 476 * 477 * @internal Hooked at PHP_INT_MAX on a Views SQL filter only while a paired 478 * chart reads its Views, including extension-provided content types. 479 * 480 * @param string $query Views SQL. 481 * @return string 482 */ 483 public static function tag_paired_views_sql( $query ) { 484 if ( ! is_string( $query ) || $query === '' || ! class_exists( 'Post_Views_Counter_Visits_Query' ) ) 485 return $query; 486 487 // an md5 hex key, so the comment cannot close early 488 return $query . ' /* pvc-visits-read ' . Post_Views_Counter_Visits_Query::get_read_cache_key( 'paired_views' ) . ' */'; 489 } 490 491 /** 492 * Read the paired post Visit series for every counted post type at once. 493 * 494 * This is an internal dashboard reader, not a public helper: it exists so a 495 * widget can draw Visits beside Views without adding one Visit query per 496 * dimension. Exactly one bounded, cached query runs per widget request no 497 * matter how many post types are counted, and a database failure is 498 * reported as unavailable rather than measured zero. 499 * 500 * @global object $wpdb 501 * 502 * @param array $args Post types, the dashboard views_query, and the period. 503 * @return array Availability plus visits keyed by post type and period. 504 */ 505 public function get_paired_visit_series( $args = [] ) { 506 global $wpdb; 507 508 $args = wp_parse_args( $args, [ 509 'post_types' => [], 510 'views_query' => [], 511 'period' => '', 512 'lang' => '' 513 ] ); 514 515 $availability = $this->get_dashboard_visits_availability(); 516 $buckets = $this->get_chart_buckets( $args['views_query'] ); 517 $post_types = array_values( array_filter( array_map( 'sanitize_key', (array) $args['post_types'] ) ) ); 518 $empty = [ 'available' => false, 'reason' => $availability['reason'], 'periods' => [], 'values' => [] ]; 519 520 if ( ! $availability['readable'] ) 521 return $empty; 522 523 if ( $buckets === null ) 524 return array_merge( $empty, [ 'reason' => 'invalid_period' ] ); 525 526 // no counted post type means nothing to pair, but the series is still 527 // readable: every bucket is a measured zero 528 if ( empty( $post_types ) ) 529 return [ 'available' => true, 'reason' => 'ready', 'periods' => $buckets['periods'], 'values' => [] ]; 530 531 // bucket keys share their row type's width (Ymd daily, Ym monthly), so the 532 // (type, period) key serves the range instead of a cast scan 533 $periods = array_map( 'strval', $buckets['periods'] ); 534 sort( $periods, SORT_STRING ); 535 $where = [ 'pvc.`type` = %d', 'pvc.`period` BETWEEN %s AND %s' ]; 536 $params = [ $buckets['type'], reset( $periods ), end( $periods ) ]; 537 538 // tables with a content dimension identify post rows as 0 539 if ( pvc_post_views_has_content_column() ) 540 $where[] = 'pvc.`content` = 0'; 541 542 $where[] = 'wpp.post_type IN (' . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ')'; 543 $params = array_merge( $params, $post_types ); 544 545 $query = $wpdb->prepare( 546 'SELECT pvc.`period`, wpp.post_type, SUM(pvc.`visits`) AS post_visits 547 FROM `' . $wpdb->prefix . 'post_views` pvc 548 INNER JOIN `' . $wpdb->posts . '` wpp ON wpp.ID = pvc.id 549 WHERE ' . implode( ' AND ', $where ) . ' 550 GROUP BY pvc.`period`, wpp.post_type', 551 $params 552 ); 553 554 // Additive companion to pvc_get_views_query_sql. It exists so the 555 // translation integrations can scope the paired Visit read exactly as 556 // they already scope the Views read; the `wpp` alias is deliberate. 557 $query = apply_filters( 'pvc_dashboard_visit_series_sql', $query, $args, $buckets ); 558 559 // keyed by the Visits generation, so every committed write, cleanup or state 560 // change retires it, not only its lifetime 561 $cache_key = Post_Views_Counter_Visits_Query::get_read_cache_key( 'dashboard_visit_series|' . $query ); 562 $values = wp_cache_get( $cache_key, Post_Views_Counter_Visits_Query::VISITS_CACHE_GROUP ); 563 564 if ( $values === false ) { 565 $wpdb->last_error = ''; 566 $rows = $wpdb->get_results( $query, ARRAY_A ); 567 568 // a failed read is unavailable, never a measured zero 569 if ( $wpdb->last_error !== '' ) 570 return array_merge( $empty, [ 'reason' => 'database_error' ] ); 571 572 $values = []; 573 574 foreach ( (array) $rows as $row ) { 575 if ( ! isset( $row['post_type'], $row['period'] ) ) 576 continue; 577 578 $values[(string) $row['post_type']][(string) $row['period']] = isset( $row['post_visits'] ) ? (int) $row['post_visits'] : 0; 579 } 580 581 wp_cache_add( $cache_key, $values, Post_Views_Counter_Visits_Query::VISITS_CACHE_GROUP, absint( apply_filters( 'pvc_object_cache_expire', 300 ) ) ); 582 } 583 584 return [ 'available' => true, 'reason' => 'ready', 'periods' => $buckets['periods'], 'values' => $values ]; 585 } 586 587 /** 588 * Flatten one dimension of a paired Visit series into chart order. 589 * 590 * @param array $series Result of get_paired_visit_series(). 591 * @param string $dimension Dimension key, or an empty string for the total. 592 * @return array 593 */ 594 private function get_visit_series_values( $series, $dimension = '' ) { 595 $values = []; 596 597 foreach ( $series['periods'] as $period ) { 598 $value = 0; 599 600 if ( $dimension === '' ) { 601 foreach ( $series['values'] as $dimension_values ) { 602 $value += isset( $dimension_values[$period] ) ? (int) $dimension_values[$period] : 0; 603 } 604 } else { 605 $value = isset( $series['values'][$dimension][$period] ) ? (int) $series['values'][$dimension][$period] : 0; 606 } 607 608 // a readable bucket with no stored row is a measured zero 609 $values[] = $value; 610 } 611 612 return $values; 613 } 614 615 /** 616 * Describe the two metric buttons of a paired dashboard widget. 617 * 618 * Core owns the shared metric control and therefore its copy, so both 619 * plugins show the same two translated labels. 620 * 621 * @param bool $visits_available Whether the Visit series can be drawn. 622 * @param string $reason Availability reason. 623 * @return array 624 */ 625 public function get_metric_buttons( $visits_available, $reason = 'ready' ) { 626 $pvc = Post_Views_Counter(); 627 $views_style = $pvc->functions->get_metric_dataset_style( 'views', 'line' ); 628 $visits_style = $pvc->functions->get_metric_dataset_style( 'visits', 'line' ); 629 630 return [ 631 [ 632 'key' => 'views', 633 'label' => _x( 'Views', 'dashboard chart metric', 'post-views-counter' ), 634 'available' => true, 635 'reason' => 'ready', 636 'color' => $views_style['borderColor'], 637 'dashed' => false 638 ], 639 [ 640 'key' => 'visits', 641 'label' => _x( 'Visits', 'dashboard chart metric', 'post-views-counter' ), 642 'available' => (bool) $visits_available, 643 'reason' => $reason, 644 'color' => $visits_style['borderColor'], 645 'dashed' => true 646 ] 647 ]; 648 } 649 650 /** 269 651 * Render dashboard widget with post views. 270 652 * … … 278 660 $period = isset( $_POST['period'] ) && ! empty( $_POST['period'] ) ? preg_replace( '/[^a-z0-9_|]/', '', $_POST['period'] ) : apply_filters( 'pvc_dashboard_widget_default_period', 'this_month', 'post-views' ); 279 661 662 echo wp_json_encode( $this->get_post_views_chart_data( $period ) ); 663 exit; 664 } 665 666 /** 667 * Build the paired post views widget payload. 668 * 669 * Separated from the AJAX handler so the payload can be asserted without 670 * the transport. The response contract, filters and arguments are unchanged. 671 * 672 * @param string $period Requested period. 673 * @return array 674 */ 675 public function get_post_views_chart_data( $period ) { 676 $period = preg_replace( '/[^a-z0-9_|]/', '', (string) $period ); 677 280 678 // get post types 281 679 $post_types = Post_Views_Counter()->options['general']['post_types_count']; 282 680 283 681 // empty options? 284 682 if ( empty( $post_types ) || ! is_array( $post_types ) ) … … 290 688 // get dashboard user options 291 689 $user_options = $this->get_dashboard_user_options( get_current_user_id(), 'post_types' ); 292 690 293 691 // empty options? 294 692 if ( empty( $user_options ) || ! is_array( $user_options ) ) … … 300 698 // get colors 301 699 $colors = Post_Views_Counter()->functions->get_colors(); 302 700 303 701 // parameters to be used in filter 304 702 $args = [ … … 308 706 'user_options' => $user_options 309 707 ]; 310 708 311 709 $data = [ 312 710 'widget' => 'post-views', 711 // The flat design object is the legacy third-party contract. First 712 // party datasets carry their own style and no longer read it. 313 713 'design' => [ 314 714 'fill' => true, … … 322 722 ], 323 723 'data' => [ 324 'datasets' => [ 325 [ 326 'label' => __( 'Total Views', 'post-views-counter' ), 327 'post_type' => '_pvc_total_views', 328 'hidden' => in_array( '_pvc_total_views', $user_options, true ), 329 'data' => [] 330 ] 331 ] 724 'datasets' => [] 332 725 ], 333 726 ]; 334 727 335 728 // convert period 336 729 $time = pvc_period2timestamp( $period ); … … 357 750 $data['dates'] = $this->generate_months( $time ); 358 751 752 // the Views query this request actually reads, so the paired Visit read 753 // uses the same grain an extension may have switched it to 754 $visits_views_query = [ 755 'year' => $year, 756 'month' => $month, 757 'hide_empty' => true 758 ]; 759 359 760 // generate chart data 360 761 $sum = []; 762 $views_datasets = []; 763 $dimensions = []; 764 765 // whether every dimension reads the query Core built 766 $core_chart = true; 767 768 $views_datasets[] = [ 769 'label' => __( 'Total Views', 'post-views-counter' ), 770 'metric' => 'views', 771 'post_type' => '_pvc_total_views', 772 'dimension_hidden' => in_array( '_pvc_total_views', $user_options, true ), 773 'hidden' => in_array( '_pvc_total_views', $user_options, true ), 774 'data' => [] 775 ]; 361 776 362 777 // any post types? … … 366 781 367 782 $post_type_data = []; 783 784 // the Views reads share the Visits series' freshness boundary 785 $tag_views = ! empty( $this->get_dashboard_visits_availability()['readable'] ); 786 787 if ( $tag_views ) 788 add_filter( 'pvc_get_views_query_sql', [ __CLASS__, 'tag_paired_views_sql' ], PHP_INT_MAX ); 368 789 369 790 foreach ( $post_types as $id => $post_type ) { … … 376 797 $label = $post_type_obj->labels->name; 377 798 378 $data['data']['datasets'][$id]['label'] = $label; 379 $data['data']['datasets'][$id]['post_type'] = $post_type; 380 $data['data']['datasets'][$id]['hidden'] = in_array( $post_type, $user_options, true ); 381 $data['data']['datasets'][$id]['data'] = []; 799 $dimensions[$id] = [ 'key' => $post_type, 'label' => $label ]; 800 801 $views_datasets[$id] = [ 802 'label' => $label, 803 'metric' => 'views', 804 'post_type' => $post_type, 805 'dimension_hidden' => in_array( $post_type, $user_options, true ), 806 'hidden' => in_array( $post_type, $user_options, true ), 807 'data' => [] 808 ]; 809 810 $core_query_args = [ 811 'fields' => 'date=>views', 812 'post_type' => $post_type, 813 'views_query' => [ 814 'year' => $year, 815 'month' => $month, 816 'hide_empty' => true 817 ] 818 ]; 819 820 $query_args = apply_filters( 'pvc_dashboard_post_views_query_args', $core_query_args, $period ); 821 822 // any dimension a filter changed (its content, grain, language or 823 // anything else) makes a chart the Free notice cannot describe 824 if ( $query_args !== $core_query_args ) 825 $core_chart = false; 826 827 // every dimension reads the same grain, so the paired Visit read 828 // follows whatever the filter settled on 829 if ( isset( $query_args['views_query'] ) && is_array( $query_args['views_query'] ) ) 830 $visits_views_query = $query_args['views_query']; 831 832 if ( isset( $query_args['lang'] ) ) 833 $args['lang'] = $query_args['lang']; 382 834 383 835 // get month views 384 $post_type_data[$id] = array_values( 385 pvc_get_views( apply_filters( 'pvc_dashboard_post_views_query_args', 386 [ 387 'fields' => 'date=>views', 388 'post_type' => $post_type, 389 'views_query' => [ 390 'year' => $year, 391 'month' => $month, 392 'hide_empty' => true 393 ] 394 ], $period 395 ) ) 396 ); 836 $post_type_data[$id] = array_values( pvc_get_views( $query_args ) ); 397 837 } 838 839 if ( $tag_views ) 840 remove_filter( 'pvc_get_views_query_sql', [ __CLASS__, 'tag_paired_views_sql' ], PHP_INT_MAX ); 398 841 399 842 foreach ( $post_type_data as $post_type_id => $post_views ) { 400 843 foreach ( $post_views as $id => $views ) { 401 844 // generate chart data for specific post types 402 $ data['data']['datasets'][$post_type_id]['data'][] = $views;845 $views_datasets[$post_type_id]['data'][] = $views; 403 846 404 847 if ( ! array_key_exists( $id, $sum ) ) … … 409 852 } 410 853 } 854 855 // One bounded, cached read covers every dimension and the total, so the 856 // paired payload never costs one extra Visit query per dimension. 857 $visit_series = $this->get_paired_visit_series( [ 858 'post_types' => array_values( $post_types ), 859 'views_query' => $visits_views_query, 860 'period' => $period, 861 'lang' => isset( $args['lang'] ) ? $args['lang'] : '' 862 ] ); 863 864 $visits_available = ! empty( $visit_series['available'] ); 865 $visits_sum = $visits_available ? $this->get_visit_series_values( $visit_series ) : []; 411 866 412 867 // this month all days … … 415 870 $data['data']['labels'][] = ( $i % 2 === 0 ? '' : $i ); 416 871 $data['data']['dates'][] = date_i18n( get_option( 'date_format' ), strtotime( $year . '-' . $month . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) ) ); 417 $data['data']['datasets'][0]['data'][] = ( array_key_exists( $i - 1, $sum ) ? $sum[$i - 1] : 0 ); 418 } 419 420 echo wp_json_encode( apply_filters( 'pvc_dashboard_post_views_data', $data, $args ) ); 421 exit; 872 $views_datasets[0]['data'][] = ( array_key_exists( $i - 1, $sum ) ? $sum[$i - 1] : 0 ); 873 } 874 875 // Visits are paired with Views on every request even when the initial 876 // mode only draws the two totals, so a metric switch never refetches. 877 $visits_datasets = []; 878 879 if ( $visits_available ) { 880 $visits_datasets[] = [ 881 'label' => __( 'Total Visits', 'post-views-counter' ), 882 'metric' => 'visits', 883 'post_type' => '_pvc_total_views', 884 'dimension_hidden' => in_array( '_pvc_total_views', $user_options, true ), 885 'hidden' => true, 886 'data' => array_slice( $visits_sum, 0, $dates_number ) 887 ]; 888 889 foreach ( $dimensions as $id => $dimension ) { 890 $visits_datasets[] = [ 891 'label' => $dimension['label'], 892 'metric' => 'visits', 893 'post_type' => $dimension['key'], 894 'dimension_hidden' => in_array( $dimension['key'], $user_options, true ), 895 'hidden' => true, 896 'data' => array_slice( $this->get_visit_series_values( $visit_series, $dimension['key'] ), 0, $dates_number ) 897 ]; 898 } 899 } 900 901 // the helper also writes the metric state onto $data by reference, so 902 // the assignment is deliberately kept as its own statement 903 $datasets = $this->prepare_metric_datasets( $views_datasets, $visits_datasets, [ 904 'widget' => 'post-views', 905 'available' => $visits_available, 906 'reason' => isset( $visit_series['reason'] ) ? $visit_series['reason'] : 'read_failed' 907 ], $data ); 908 909 $data['data']['datasets'] = $datasets; 910 911 // The Free Views comparison, only on the month chart Core drew 912 // itself, with every dimension's query as built, and never 913 // beside an active extension of any version, which decides the list on its 914 // own. No list means no box. 915 if ( ! class_exists( 'Post_Views_Counter_Pro' ) && $core_chart ) { 916 $insight_notices = $this->get_free_insight_notices( $year . $month, array_values( $post_types ) ); 917 918 if ( ! empty( $insight_notices ) ) 919 $data['insight_notices'] = $insight_notices; 920 } 921 922 $data = apply_filters( 'pvc_dashboard_post_views_data', $data, $args ); 923 924 // The headline describes the final chart's total, regardless of dataset 925 // order or visibility. An explicit summary (including null) stays owned 926 // by the filter; an unreadable series never becomes an invented zero. 927 if ( ! class_exists( 'Post_Views_Counter_Pro' ) && is_array( $data ) && ! array_key_exists( 'summary', $data ) && isset( $data['data']['datasets'] ) && is_array( $data['data']['datasets'] ) ) { 928 foreach ( $data['data']['datasets'] as $dataset ) { 929 if ( ! is_array( $dataset ) || ! isset( $dataset['metric'], $dataset['post_type'] ) || $dataset['metric'] !== 'views' || $dataset['post_type'] !== '_pvc_total_views' ) 930 continue; 931 932 if ( empty( $dataset['data'] ) || ! is_array( $dataset['data'] ) ) 933 break; 934 935 $views = 0; 936 937 foreach ( $dataset['data'] as $value ) { 938 if ( ! is_numeric( $value ) || ! is_finite( (float) $value ) ) 939 break 2; 940 941 $views += $value; 942 } 943 944 if ( is_finite( (float) $views ) ) { 945 $data['summary'] = [ 946 'views' => $views, 947 'views_html' => html_entity_decode( number_format_i18n( $views ), ENT_NOQUOTES, 'UTF-8' ) 948 ]; 949 } 950 951 break; 952 } 953 } 954 955 // formatted after the filter, so tooltips match the values it returns 956 if ( is_array( $data ) && isset( $data['data'] ) ) 957 $data['data'] = Post_Views_Counter()->functions->format_chart_datasets( $data['data'] ); 958 959 return $data; 960 } 961 962 /** 963 * Build the Free Views comparison notice. 964 * 965 * The month drawn against the previous month, on the shared comparison 966 * of the counted post types, with no language and no history: a 967 * running month on its completed days, a complete one on whole months. 968 * - No valid comparison: null, so the payload has no list and no box. 969 * - Fewer than FREE_NOTICE_MIN_VIEWS Views on either side: an empty list, no box. 970 * - Otherwise the direction and the rounded change. A 971 * running month is "This month" against the same days last month; a 972 * complete one is named against the month before it. A change that 973 * rounds to 0 reads "less than 1%"; equal Views read "level with". 974 * 975 * @param string $period The month drawn, YYYYMM. 976 * @param array $post_types Counted post types. 977 * @return array|null The `insight_notices` list. 978 */ 979 private function get_free_insight_notices( $period, $post_types ) { 980 $comparison = Post_Views_Counter_Dashboard_Comparison::get( [ 981 'grain' => 'month', 982 'period' => $period, 983 'scope' => 'posts', 984 'post_types' => $post_types, 985 'now' => $this->now 986 ] ); 987 988 if ( empty( $comparison['available'] ) ) 989 return null; 990 991 $notices = []; 992 $current = (int) $comparison['current']['views']; 993 $previous = (int) $comparison['previous']['views']; 994 995 if ( $current >= self::FREE_NOTICE_MIN_VIEWS && $previous >= self::FREE_NOTICE_MIN_VIEWS ) { 996 // a running month compares its completed days with the same days 997 // of the month before, named relatively, never as a range of days 998 $running = $comparison['state'] !== 'complete'; 999 $month = self::format_comparison_month( $comparison['current']['from'] ); 1000 $previous_month = self::format_comparison_month( $comparison['previous']['from'] ); 1001 1002 if ( $current === $previous ) { 1003 $direction = 'same'; 1004 $text = $running 1005 ? __( 'This month is level with the same days last month.', 'post-views-counter' ) 1006 /* translators: 1: the month the chart shows, e.g. June 2026, 2: the month before it */ 1007 : sprintf( __( '%1$s was level with %2$s.', 'post-views-counter' ), self::ucfirst( $month ), $previous_month ); 1008 } else { 1009 $direction = $current > $previous ? 'up' : 'down'; 1010 1011 // half away from zero; whole-number inputs keep 0.5% exact 1012 $percent = (int) round( abs( $current - $previous ) * 100 / $previous ); 1013 1014 if ( $percent < 1 ) 1015 $change = __( 'less than 1%', 'post-views-counter' ); 1016 else 1017 /* translators: %s: a change in percent, a whole number without a sign */ 1018 $change = sprintf( __( '%s%%', 'post-views-counter' ), number_format_i18n( $percent ) ); 1019 1020 if ( $running ) { 1021 $text = $direction === 'up' 1022 /* translators: %s: the change, e.g. 12% */ 1023 ? sprintf( __( 'This month is %s higher than the same days last month.', 'post-views-counter' ), $change ) 1024 /* translators: %s: the change, e.g. 12% */ 1025 : sprintf( __( 'This month is %s lower than the same days last month.', 'post-views-counter' ), $change ); 1026 } else { 1027 $text = $direction === 'up' 1028 /* translators: 1: the month the chart shows, e.g. June 2026, 2: the change, e.g. 12%, 3: the month before it */ 1029 ? sprintf( __( '%1$s was %2$s higher than %3$s.', 'post-views-counter' ), self::ucfirst( $month ), $change, $previous_month ) 1030 /* translators: 1: the month the chart shows, e.g. June 2026, 2: the change, e.g. 12%, 3: the month before it */ 1031 : sprintf( __( '%1$s was %2$s lower than %3$s.', 'post-views-counter' ), self::ucfirst( $month ), $change, $previous_month ); 1032 } 1033 } 1034 1035 $notices[] = [ 1036 'family' => 'views', 1037 'class' => 'comparison', 1038 'direction' => $direction, 1039 'text' => $text 1040 ]; 1041 } 1042 1043 return $notices; 1044 } 1045 1046 /** 1047 * Name a whole month of a comparison, e.g. "June 2026". 1048 * 1049 * Ranges are counting-clock buckets, so they are formatted as UTC days and 1050 * never shifted by the site timezone. 1051 * 1052 * @param string $from Its first day, Ymd. 1053 * @return string 1054 */ 1055 private static function format_comparison_month( $from ) { 1056 $utc = new DateTimeZone( 'UTC' ); 1057 1058 return wp_date( _x( 'F Y', 'dashboard comparison: a month', 'post-views-counter' ), DateTimeImmutable::createFromFormat( '!Ymd', $from, $utc )->getTimestamp(), $utc ); 1059 } 1060 1061 /** 1062 * Capitalise the first letter of a sentence's subject, for locales whose 1063 * month names are lowercase. 1064 * 1065 * @param string $text 1066 * @return string 1067 */ 1068 private static function ucfirst( $text ) { 1069 if ( $text === '' || ! function_exists( 'mb_substr' ) ) 1070 return ucfirst( $text ); 1071 1072 return mb_strtoupper( mb_substr( $text, 0, 1, 'UTF-8' ), 'UTF-8' ) . mb_substr( $text, 1, null, 'UTF-8' ); 1073 } 1074 1075 /** 1076 * Attach the paired metric state, styles, and copy to a widget payload. 1077 * 1078 * Views datasets come first and Visits second so Chart.js draws the derived 1079 * colour in front of the theme colour in the totals pair. 1080 * 1081 * @param array $views_datasets Ordered Views datasets. 1082 * @param array $visits_datasets Ordered Visits datasets, empty when unreadable. 1083 * @param array $context Widget id and Visit availability. 1084 * @param array $data Payload being built, passed by reference. 1085 * @return array Combined, styled datasets. 1086 */ 1087 public function prepare_metric_datasets( $views_datasets, $visits_datasets, $context, &$data ) { 1088 $pvc = Post_Views_Counter(); 1089 $context = wp_parse_args( $context, [ 1090 'widget' => '', 1091 'available' => false, 1092 'reason' => 'read_failed' 1093 ] ); 1094 1095 $available = (bool) $context['available']; 1096 $preferred = $this->get_widget_metric_mode( $context['widget'], get_current_user_id() ); 1097 1098 // An unreadable Visit series forces the Views breakdown for this render 1099 // only. The stored preference is never rewritten, so the preferred mode 1100 // returns by itself once Visits becomes readable again. 1101 $effective = $available ? $preferred : 'views'; 1102 1103 $datasets = []; 1104 1105 foreach ( [ 'views' => $views_datasets, 'visits' => $visits_datasets ] as $metric => $metric_datasets ) { 1106 foreach ( $metric_datasets as $index => $dataset ) { 1107 $dataset['metric'] = $metric; 1108 $dataset['is_total'] = $index === 0; 1109 1110 if ( $effective === 'both' ) { 1111 // both totals are always drawn and the saved breakdown 1112 // visibility of Total is deliberately not consulted 1113 $dataset['hidden'] = $index !== 0; 1114 } else { 1115 $dataset['hidden'] = $metric !== $effective || ! empty( $dataset['dimension_hidden'] ); 1116 } 1117 1118 // The translucent area is part of the dashboard presentation in all 1119 // three metric modes, including multi-line breakdowns. 1120 $datasets[] = array_merge( $dataset, $pvc->functions->get_metric_dataset_style( $metric, 'line', [ 'fill' => true ] ) ); 1121 } 1122 } 1123 1124 $data['metrics'] = $this->get_metric_buttons( $available, $context['reason'] ); 1125 $data['metric_state'] = [ 1126 'preferred' => $preferred, 1127 'effective' => $effective 1128 ]; 1129 $data['availability'] = [ 1130 'readable' => $available, 1131 'reason' => $available ? 'ready' : $context['reason'] 1132 ]; 1133 $data['notices'] = [ 1134 'visits_unavailable' => __( 'Visit data is not available right now.', 'post-views-counter' ) 1135 ]; 1136 1137 return $datasets; 422 1138 } 423 1139 … … 431 1147 wp_die( __( 'You do not have permission to access this page.', 'post-views-counter' ) ); 432 1148 433 // get main instance 434 $pvc = Post_Views_Counter(); 1149 // get period 1150 $period = isset( $_POST['period'] ) && ! empty( $_POST['period'] ) ? preg_replace( '/[^a-z0-9_|]/', '', $_POST['period'] ) : apply_filters( 'pvc_dashboard_widget_default_period', 'this_month', 'post-most-viewed' ); 1151 1152 echo wp_json_encode( $this->get_post_most_viewed_data( $period ) ); 1153 exit; 1154 } 1155 1156 /** 1157 * Build the Top Posts widget payload. 1158 * 1159 * Separated from the AJAX handler so the list can be asserted without the 1160 * transport. Rows are selected, ordered and ranked by Views. 1161 * 1162 * @param string $period Requested period. 1163 * @return array 1164 */ 1165 public function get_post_most_viewed_data( $period ) { 1166 $period = preg_replace( '/[^a-z0-9_|]/', '', (string) $period ); 435 1167 436 1168 // get post types … … 444 1176 $post_types = map_deep( $post_types, 'sanitize_text_field' ); 445 1177 446 // get period447 $period = isset( $_POST['period'] ) && ! empty( $_POST['period'] ) ? preg_replace( '/[^a-z0-9_|]/', '', $_POST['period'] ) : apply_filters( 'pvc_dashboard_widget_default_period', 'this_month', 'post-most-viewed' );448 449 1178 // parameters to be used in filter 450 1179 $args = [ … … 488 1217 489 1218 $posts = pvc_get_most_viewed_posts( $query_args ); 490 1219 491 1220 $html = ' 492 1221 <table id="pvc-post-most-viewed-table" class="pvc-table pvc-table-hover"> … … 550 1279 $data['html'] = $html; 551 1280 552 echo wp_json_encode( apply_filters( 'pvc_dashboard_post_most_viewed_data', $data, $args ) ); 553 exit; 1281 return apply_filters( 'pvc_dashboard_post_most_viewed_data', $data, $args ); 554 1282 } 555 1283 … … 600 1328 $user_id = get_current_user_id(); 601 1329 602 // get user dashboard data 603 $user_options = get_user_meta( $user_id, 'pvc_dashboard', true ); 604 605 // empty userdata? 606 if ( ! is_array( $user_options ) || empty( $user_options ) ) 607 $user_options = []; 608 609 // empty post types? 610 if ( ! array_key_exists( 'post_types', $user_options ) || ! is_array( $user_options['post_types'] ) ) 611 $user_options['post_types'] = []; 612 613 // hide post type? 614 if ( ! empty( $update['post_type'] ) ) { 615 // get allowed post types 616 $allowed_post_types = Post_Views_Counter()->options['general']['post_types_count']; 617 618 // simulate total post views as post type 619 $allowed_post_types[] = '_pvc_total_views'; 620 621 if ( in_array( $update['post_type'], $allowed_post_types, true ) ) { 622 if ( isset( $update['hidden'] ) && $update['hidden'] === 'true' ) { 623 if ( ! in_array( $update['post_type'], $user_options['post_types'], true ) ) 624 $user_options['post_types'][] = $update['post_type']; 625 } else { 626 if ( ( $key = array_search( $update['post_type'], $user_options['post_types'] ) ) !== false ) 627 unset( $user_options['post_types'][$key] ); 628 } 1330 // update userdata 1331 update_user_meta( $user_id, 'pvc_dashboard', $this->merge_dashboard_user_options( $update, $user_id ) ); 1332 1333 echo wp_send_json_success(); 1334 } 1335 1336 echo wp_send_json_error(); 1337 exit; 1338 } 1339 1340 /** 1341 * Merge one dashboard preference update into the stored user options. 1342 * 1343 * Separated from the AJAX handler so the allow-lists can be asserted 1344 * without the transport. The stored shape and the filter are unchanged. 1345 * 1346 * @param array $update Sanitized update payload. 1347 * @param int $user_id User ID. 1348 * @return array 1349 */ 1350 public function merge_dashboard_user_options( $update, $user_id ) { 1351 $update = is_array( $update ) ? $update : []; 1352 1353 // get user dashboard data 1354 $user_options = get_user_meta( $user_id, 'pvc_dashboard', true ); 1355 1356 // empty userdata? 1357 if ( ! is_array( $user_options ) || empty( $user_options ) ) 1358 $user_options = []; 1359 1360 // empty post types? 1361 if ( ! array_key_exists( 'post_types', $user_options ) || ! is_array( $user_options['post_types'] ) ) 1362 $user_options['post_types'] = []; 1363 1364 // hide post type? 1365 if ( ! empty( $update['post_type'] ) ) { 1366 // get allowed post types 1367 $allowed_post_types = Post_Views_Counter()->options['general']['post_types_count']; 1368 1369 // simulate total post views as post type 1370 $allowed_post_types[] = '_pvc_total_views'; 1371 1372 if ( in_array( $update['post_type'], $allowed_post_types, true ) ) { 1373 if ( isset( $update['hidden'] ) && $update['hidden'] === 'true' ) { 1374 if ( ! in_array( $update['post_type'], $user_options['post_types'], true ) ) 1375 $user_options['post_types'][] = $update['post_type']; 1376 } else { 1377 if ( ( $key = array_search( $update['post_type'], $user_options['post_types'] ) ) !== false ) 1378 unset( $user_options['post_types'][$key] ); 629 1379 } 630 1380 } 631 632 // empty menu items? 633 if ( ! array_key_exists( 'menu_items', $user_options ) || ! is_array( $user_options['menu_items'] ) ) 634 $user_options['menu_items'] = []; 635 636 if ( ! empty( $update['menu_items'] ) && is_array( $update['menu_items'] ) ) { 637 $user_options['menu_items'] = []; 638 639 // get allowed menu items 640 $allowed_menu_items = array_column( $this->widget_items, 'id' ); 641 642 foreach ( $update['menu_items'] as $menu_item => $hidden ) { 643 if ( in_array( $menu_item, $allowed_menu_items, true ) && $hidden === 'true' ) 644 $user_options['menu_items'][] = $menu_item; 645 } 1381 } 1382 1383 // empty metric modes? 1384 if ( ! array_key_exists( 'metrics', $user_options ) || ! is_array( $user_options['metrics'] ) ) 1385 $user_options['metrics'] = []; 1386 1387 // Only an explicit metric-button action reaches this branch. An 1388 // availability fallback renders in Views breakdown mode without ever 1389 // sending an update, so a stored both or visits preference survives 1390 // a Visits outage untouched. 1391 if ( ! empty( $update['metrics'] ) && is_array( $update['metrics'] ) ) { 1392 // the widget list is normally built on admin_init; build it here too 1393 // so the allow-list is never silently empty 1394 if ( empty( $this->widget_items ) ) 1395 $this->setup_widget_items(); 1396 1397 $allowed_widgets = array_column( $this->widget_items, 'id' ); 1398 1399 foreach ( $update['metrics'] as $widget_id => $mode ) { 1400 $widget_id = sanitize_key( $widget_id ); 1401 1402 if ( in_array( $widget_id, $allowed_widgets, true ) && in_array( $mode, $this->get_metric_modes(), true ) ) 1403 $user_options['metrics'][$widget_id] = $mode; 646 1404 } 647 648 // filter user options 649 $user_options = apply_filters( 'pvc_update_dashboard_user_options', $user_options, $update, $user_id ); 650 651 // update userdata 652 update_user_meta( $user_id, 'pvc_dashboard', $user_options ); 653 654 echo wp_send_json_success(); 655 } 656 657 echo wp_send_json_error(); 658 exit; 1405 } 1406 1407 // empty menu items? 1408 if ( ! array_key_exists( 'menu_items', $user_options ) || ! is_array( $user_options['menu_items'] ) ) 1409 $user_options['menu_items'] = []; 1410 1411 if ( ! empty( $update['menu_items'] ) && is_array( $update['menu_items'] ) ) { 1412 $user_options['menu_items'] = []; 1413 1414 // get allowed menu items 1415 $allowed_menu_items = array_column( $this->widget_items, 'id' ); 1416 1417 foreach ( $update['menu_items'] as $menu_item => $hidden ) { 1418 if ( in_array( $menu_item, $allowed_menu_items, true ) && $hidden === 'true' ) 1419 $user_options['menu_items'][] = $menu_item; 1420 } 1421 } 1422 1423 // filter user options 1424 $user_options = apply_filters( 'pvc_update_dashboard_user_options', $user_options, $update, $user_id ); 1425 1426 return $user_options; 659 1427 } 660 1428 -
post-views-counter/tags/1.8.0/includes/class-emails-mailer.php
r3537950 r3734102 62 62 63 63 try { 64 $this->maybe_flush_pending_counts( $context ); 64 $flush_result = $this->maybe_flush_pending_counts( $context ); 65 66 if ( is_wp_error( $flush_result ) ) 67 return $this->finalize_failure( $this->get_default_result( $context['recipient'], [], [] ), 'pending_counts_not_flushed', $flush_result, $context['settings'], $context['period'], $context['source'], $context['is_test'], $context['summary_type'] ); 65 68 66 69 $rendered = $this->emails->render_summary( … … 290 293 * 291 294 * @param array $context 292 * @return void295 * @return true|WP_Error 293 296 */ 294 297 private function maybe_flush_pending_counts( $context ) { 295 298 if ( ! $this->should_flush_pending_counts( $context ) ) 296 return ;299 return true; 297 300 298 301 $counter = isset( $this->pvc->counter ) ? $this->pvc->counter : null; 299 302 $should_flush_base_counts = (bool) apply_filters( 'pvc_email_summary_should_flush_pending_counts', true, $context, $this ); 300 303 301 if ( $should_flush_base_counts && $counter && method_exists( $counter, 'using_object_cache' ) && method_exists( $counter, 'flush_cache_to_db' ) && $counter->using_object_cache() ) 302 $counter->flush_cache_to_db(); 304 if ( $should_flush_base_counts && $counter && method_exists( $counter, 'flush_cache_to_db' ) && ! $counter->flush_cache_to_db() ) { 305 $status = method_exists( $counter, 'get_cache_flush_status' ) ? sanitize_key( $counter->get_cache_flush_status() ) : 'failed'; 306 307 return new WP_Error( 'pvc_email_pending_counts_' . $status, __( 'Pending view counts could not be flushed before the summary query.', 'post-views-counter' ) ); 308 } 303 309 304 310 do_action( 'pvc_email_summary_before_query', $context, $this ); 311 312 return true; 305 313 } 306 314 -
post-views-counter/tags/1.8.0/includes/class-emails-query.php
r3537950 r3734102 10 10 */ 11 11 class Post_Views_Counter_Emails_Query { 12 13 /** 14 * Most ISO weeks a filtered day range may touch and still be proven complete. 15 * Six cover any range of up to 31 days 16 * however it falls; the built-in cadences touch one week per range. A longer 17 * range is read without week checks and is unestablished. 18 * 19 * @var int 20 */ 21 const MAX_CHECKED_WEEKS = 6; 12 22 13 23 /** … … 207 217 208 218 $overview_trend = $this->build_trend_data( $current['total_views'], $previous['total_views'] ); 219 220 // a comparison with a range that cannot be shown complete is not a trend 221 if ( ! $current['complete'] || ! $previous['complete'] ) { 222 $overview_trend = $this->build_trend_data( $current['total_views'], 0 ); 223 $overview_trend['views_change'] = (int) $current['total_views'] - (int) $previous['total_views']; 224 } 225 209 226 $threshold_met = (int) $current['total_views'] >= (int) $query_args['threshold']; 210 227 $should_send = $threshold_met || $query_args['send_empty_reports']; 211 $top_content = $this->build_top_content_data( $top_items, $previous_views ); 228 $unestablished = []; 229 $top_content = $this->build_top_content_data( $top_items, $previous_views, $unestablished ); 212 230 213 231 $overview = [ … … 235 253 'overview' => $overview, 236 254 'top_content' => $top_content, 237 'traffic_signals' => $this->build_traffic_signals_data( $overview, $top_content ),255 'traffic_signals' => $this->build_traffic_signals_data( $overview, $top_content, $unestablished ), 238 256 'status' => $this->build_status_data( $overview, ! empty( $top_content ) ) 239 257 ]; … … 299 317 300 318 $post_type_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ); 301 $period_query = $this->get_period_query_parts( $start_period, $end_period ); 302 $params = array_merge( [ 0 ], $period_query['params'], [ 'publish', '' ], $post_types ); 319 $source = $this->get_range_source( $start_period, $end_period ); 320 321 if ( $source !== null && $source['type'] === 0 ) { 322 $query = $wpdb->prepare( 323 ' SELECT COALESCE( SUM( summary.period_views ), 0 ) AS total_views, COALESCE( SUM( CASE WHEN summary.period_views > 0 THEN 1 ELSE 0 END ), 0 ) AS viewed_content_count, COALESCE( SUM( summary.incomplete ), 0 ) AS incomplete_count 324 FROM ( 325 SELECT pv.id AS post_id, SUM( CASE WHEN pv.type = 0 AND pv.period >= %s AND pv.period <= %s THEN pv.count ELSE 0 END ) AS period_views, CASE WHEN ' . $source['checks'] . ' THEN 0 ELSE 1 END AS incomplete 326 FROM ' . $wpdb->prefix . 'post_views AS pv 327 INNER JOIN ' . $wpdb->posts . ' AS p ON pv.id = p.ID 328 WHERE ' . $source['where'] . $this->get_post_content_clause() . ' 329 AND p.post_status = %s 330 AND p.post_password = %s 331 AND p.post_type IN (' . $post_type_placeholders . ') 332 GROUP BY pv.id 333 ) AS summary', 334 array_merge( [ $source['from'], $source['to'] ], $source['check_params'], $source['where_params'], [ 'publish', '' ], $post_types ) 335 ); 336 337 $row = $wpdb->get_row( $query, ARRAY_A ); 338 339 return [ 340 'total_views' => isset( $row['total_views'] ) ? (int) $row['total_views'] : 0, 341 'viewed_content_count' => isset( $row['viewed_content_count'] ) ? (int) $row['viewed_content_count'] : 0, 342 'complete' => $source['checks'] !== '1 = 0' && isset( $row['incomplete_count'] ) && (int) $row['incomplete_count'] === 0 343 ]; 344 } 345 346 $period_query = $source === null ? $this->get_period_query_parts( $start_period, $end_period ) : [ 'clause' => 'pv.period = %s', 'params' => [ $source['period'] ] ]; 347 $params = array_merge( [ $source === null ? 0 : $source['type'] ], $period_query['params'], [ 'publish', '' ], $post_types ); 303 348 $query = $wpdb->prepare( 304 349 ' SELECT COALESCE( SUM( summary.period_views ), 0 ) AS total_views, COUNT( summary.post_id ) AS viewed_content_count … … 307 352 FROM ' . $wpdb->prefix . 'post_views AS pv 308 353 INNER JOIN ' . $wpdb->posts . ' AS p ON pv.id = p.ID 309 WHERE pv.type = %d 354 WHERE pv.type = %d' . $this->get_post_content_clause() . ' 310 355 AND ' . $period_query['clause'] . ' 311 356 AND p.post_status = %s … … 321 366 return [ 322 367 'total_views' => isset( $row['total_views'] ) ? (int) $row['total_views'] : 0, 323 'viewed_content_count' => isset( $row['viewed_content_count'] ) ? (int) $row['viewed_content_count'] : 0 368 'viewed_content_count' => isset( $row['viewed_content_count'] ) ? (int) $row['viewed_content_count'] : 0, 369 'complete' => true 324 370 ]; 325 371 } … … 339 385 340 386 $post_type_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ); 341 $period_query = $this->get_period_query_parts( $start_period, $end_period ); 342 $params = array_merge( [ 0 ], $period_query['params'], [ 'publish', '' ], $post_types, [ (int) $limit ] ); 387 $source = $this->get_range_source( $start_period, $end_period ); 388 389 if ( $source !== null && $source['type'] === 0 ) { 390 $query = $wpdb->prepare( 391 ' SELECT pv.id AS post_id, p.post_title AS post_title, SUM( CASE WHEN pv.type = 0 AND pv.period >= %s AND pv.period <= %s THEN pv.count ELSE 0 END ) AS current_views, CASE WHEN ' . $source['checks'] . ' THEN 1 ELSE 0 END AS complete 392 FROM ' . $wpdb->prefix . 'post_views AS pv 393 INNER JOIN ' . $wpdb->posts . ' AS p ON pv.id = p.ID 394 WHERE ' . $source['where'] . $this->get_post_content_clause() . ' 395 AND p.post_status = %s 396 AND p.post_password = %s 397 AND p.post_type IN (' . $post_type_placeholders . ') 398 GROUP BY pv.id, p.post_title 399 HAVING current_views > 0 400 ORDER BY current_views DESC, pv.id ASC 401 LIMIT %d', 402 array_merge( [ $source['from'], $source['to'] ], $source['check_params'], $source['where_params'], [ 'publish', '' ], $post_types, [ (int) $limit ] ) 403 ); 404 405 $items = $wpdb->get_results( $query, ARRAY_A ); 406 407 return is_array( $items ) ? $items : []; 408 } 409 410 $period_query = $source === null ? $this->get_period_query_parts( $start_period, $end_period ) : [ 'clause' => 'pv.period = %s', 'params' => [ $source['period'] ] ]; 411 $params = array_merge( [ $source === null ? 0 : $source['type'] ], $period_query['params'], [ 'publish', '' ], $post_types, [ (int) $limit ] ); 343 412 $query = $wpdb->prepare( 344 413 ' SELECT pv.id AS post_id, p.post_title AS post_title, SUM( pv.count ) AS current_views 345 414 FROM ' . $wpdb->prefix . 'post_views AS pv 346 415 INNER JOIN ' . $wpdb->posts . ' AS p ON pv.id = p.ID 347 WHERE pv.type = %d 416 WHERE pv.type = %d' . $this->get_post_content_clause() . ' 348 417 AND ' . $period_query['clause'] . ' 349 418 AND p.post_status = %s … … 381 450 $post_type_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ); 382 451 $post_id_placeholders = implode( ', ', array_fill( 0, count( $post_ids ), '%d' ) ); 383 $period_query = $this->get_period_query_parts( $start_period, $end_period ); 384 $params = array_merge( [ 0 ], $period_query['params'], [ 'publish', '' ], $post_types, $post_ids ); 452 $source = $this->get_range_source( $start_period, $end_period ); 453 454 // a range that is not a whole stored period counts only for posts whose ISO weeks add up 455 if ( $source !== null && $source['type'] === 0 ) { 456 $query = $wpdb->prepare( 457 ' SELECT pv.id AS post_id, SUM( CASE WHEN pv.type = 0 AND pv.period >= %s AND pv.period <= %s THEN pv.count ELSE 0 END ) AS previous_views, CASE WHEN ' . $source['checks'] . ' THEN 1 ELSE 0 END AS complete 458 FROM ' . $wpdb->prefix . 'post_views AS pv 459 INNER JOIN ' . $wpdb->posts . ' AS p ON pv.id = p.ID 460 WHERE ' . $source['where'] . $this->get_post_content_clause() . ' 461 AND p.post_status = %s 462 AND p.post_password = %s 463 AND p.post_type IN (' . $post_type_placeholders . ') 464 AND pv.id IN (' . $post_id_placeholders . ') 465 GROUP BY pv.id', 466 array_merge( [ $source['from'], $source['to'] ], $source['check_params'], $source['where_params'], [ 'publish', '' ], $post_types, $post_ids ) 467 ); 468 469 $results = $wpdb->get_results( $query, ARRAY_A ); 470 $views = []; 471 472 if ( is_array( $results ) ) { 473 foreach ( $results as $result ) { 474 if ( empty( $result['complete'] ) ) 475 $views[(int) $result['post_id']] = null; 476 elseif ( (int) $result['previous_views'] > 0 ) 477 $views[(int) $result['post_id']] = (int) $result['previous_views']; 478 } 479 } 480 481 return $views; 482 } 483 484 $period_query = $source === null ? $this->get_period_query_parts( $start_period, $end_period ) : [ 'clause' => 'pv.period = %s', 'params' => [ $source['period'] ] ]; 485 $params = array_merge( [ $source === null ? 0 : $source['type'] ], $period_query['params'], [ 'publish', '' ], $post_types, $post_ids ); 385 486 $query = $wpdb->prepare( 386 487 ' SELECT pv.id AS post_id, SUM( pv.count ) AS previous_views 387 488 FROM ' . $wpdb->prefix . 'post_views AS pv 388 489 INNER JOIN ' . $wpdb->posts . ' AS p ON pv.id = p.ID 389 WHERE pv.type = %d 490 WHERE pv.type = %d' . $this->get_post_content_clause() . ' 390 491 AND ' . $period_query['clause'] . ' 391 492 AND p.post_status = %s … … 410 511 411 512 /** 513 * Restrict the counter rows to posts when the table stores other content. 514 * 515 * @return string 516 */ 517 private function get_post_content_clause() { 518 return pvc_post_views_has_content_column() ? ' AND pv.content = 0' : ''; 519 } 520 521 /** 522 * Get where the Views of a date range are read from. 523 * 524 * A range that is exactly one ISO week or one calendar month is read from 525 * that period's own row, which the daily cleanup never deletes. Any other 526 * range is read from daily rows, and counts only while the daily rows of 527 * every ISO week it touches add up to that week's own row, checked in the same statement. 528 * 529 * @param string|int $start_period Ymd 530 * @param string|int $end_period Ymd 531 * @return array|null Own row: [ 'type' => 1|2, 'period' ]. Daily rows: 532 * [ 'type' => 0, 'from', 'to', 'where', 'where_params', 533 * 'checks', 'check_params' ]. Null when the bounds are not 534 * dates, which keeps the released clause. 535 */ 536 private function get_range_source( $start_period, $end_period ) { 537 $start = $this->normalize_date_period_value( $start_period ); 538 $end = $this->normalize_date_period_value( $end_period ); 539 540 if ( $start === '' || $end === '' ) 541 return null; 542 543 if ( $start > $end ) { 544 $temp = $start; 545 $start = $end; 546 $end = $temp; 547 } 548 549 $utc = new DateTimeZone( 'UTC' ); 550 $from = DateTimeImmutable::createFromFormat( '!Ymd', $start, $utc ); 551 $to = DateTimeImmutable::createFromFormat( '!Ymd', $end, $utc ); 552 553 if ( ! $from || ! $to || $from->format( 'Ymd' ) !== $start || $to->format( 'Ymd' ) !== $end ) 554 return null; 555 556 if ( $from->format( 'N' ) === '1' && $to->format( 'Ymd' ) === $from->modify( '+6 days' )->format( 'Ymd' ) ) 557 return [ 'type' => 1, 'period' => $from->format( 'oW' ) ]; 558 559 if ( $from->format( 'j' ) === '1' && $to->format( 'Ymd' ) === $from->format( 'Ymt' ) ) 560 return [ 'type' => 2, 'period' => $from->format( 'Ym' ) ]; 561 562 $monday = $from->modify( '-' . ( (int) $from->format( 'N' ) - 1 ) . ' days' ); 563 $last_sunday = $to->modify( '+' . ( 7 - (int) $to->format( 'N' ) ) . ' days' ); 564 $weeks = []; 565 $checks = []; 566 $check_params = []; 567 568 for ( $week = $monday; $week <= $last_sunday; $week = $week->modify( '+7 days' ) ) { 569 // Beyond the proof budget, totals remain readable but completeness is unestablished. 570 if ( count( $weeks ) >= self::MAX_CHECKED_WEEKS ) { 571 return [ 572 'type' => 0, 'from' => $start, 'to' => $end, 573 'where' => '( pv.type = 0 AND pv.period >= %s AND pv.period <= %s )', 574 'where_params' => [ $start, $end ], 575 'checks' => '1 = 0', 'check_params' => [] 576 ]; 577 } 578 579 $weeks[] = $week->format( 'oW' ); 580 $checks[] = 'SUM( CASE WHEN pv.type = 0 AND pv.period >= %s AND pv.period <= %s THEN pv.count ELSE 0 END ) = SUM( CASE WHEN pv.type = 1 AND pv.period = %s THEN pv.count ELSE 0 END )'; 581 $check_params = array_merge( $check_params, [ $week->format( 'Ymd' ), $week->modify( '+6 days' )->format( 'Ymd' ), $week->format( 'oW' ) ] ); 582 } 583 584 return [ 585 'type' => 0, 586 'from' => $start, 587 'to' => $end, 588 'where' => '( ( pv.type = 0 AND pv.period >= %s AND pv.period <= %s ) OR ( pv.type = 1 AND pv.period IN (' . implode( ', ', array_fill( 0, count( $weeks ), '%s' ) ) . ') ) )', 589 'where_params' => array_merge( [ $monday->format( 'Ymd' ), $last_sunday->format( 'Ymd' ) ], $weeks ), 590 'checks' => implode( ' AND ', $checks ), 591 'check_params' => $check_params 592 ]; 593 } 594 595 /** 412 596 * Build the period comparison clause and parameters. 413 597 * … … 464 648 * @return array 465 649 */ 466 private function build_top_content_data( $top_items, $previous_views ) {650 private function build_top_content_data( $top_items, $previous_views, &$unestablished = [] ) { 467 651 $content = []; 468 652 … … 471 655 $current_views = (int) $item['current_views']; 472 656 $item_previous_views = isset( $previous_views[$post_id] ) ? (int) $previous_views[$post_id] : 0; 473 $trend = $this->build_trend_data( $current_views, $item_previous_views ); 657 $established = ( ! isset( $item['complete'] ) || ! empty( $item['complete'] ) ) && ! ( array_key_exists( $post_id, $previous_views ) && $previous_views[$post_id] === null ); 658 $trend = $this->build_trend_data( $current_views, $established ? $item_previous_views : 0 ); 659 660 // an item whose ranges cannot be shown complete has no trend and no signal 661 if ( ! $established ) { 662 $trend['views_change'] = $current_views - $item_previous_views; 663 $unestablished[] = $post_id; 664 } 474 665 $url = get_permalink( $post_id ); 475 666 … … 529 720 * @param array $overview 530 721 * @param array $top_content 531 * @return array 532 */ 533 private function build_traffic_signals_data( $overview, $top_content ) { 722 * @param array $unestablished Post IDs whose ranges cannot be shown complete 723 * @return array 724 */ 725 private function build_traffic_signals_data( $overview, $top_content, $unestablished = [] ) { 534 726 if ( (int) $overview['total_views'] === 0 ) { 535 727 return [ … … 549 741 550 742 foreach ( $top_content as $item ) { 743 if ( ! empty( $item['post_id'] ) && in_array( (int) $item['post_id'], $unestablished, true ) ) 744 continue; 745 551 746 $current_views = isset( $item['current_views'] ) ? (int) $item['current_views'] : 0; 552 747 $previous_views = isset( $item['previous_views'] ) ? (int) $item['previous_views'] : 0; -
post-views-counter/tags/1.8.0/includes/class-frontend.php
r3640258 r3734102 42 42 */ 43 43 public function post_views_shortcode( $args ) { 44 $ views = 0;44 $html = ''; 45 45 $options = Post_Views_Counter()->options['display']; 46 $raw_args = is_array( $args ) ? $args : []; 46 47 47 48 $defaults = [ 48 49 'id' => get_the_ID(), 49 50 'type' => 'post', 50 'period' => $options['display_period'] 51 'period' => $options['display_period'], 52 'format' => null 51 53 ]; 52 54 53 55 // combine attributes 54 $atts = shortcode_atts( $defaults, $args ); 55 $atts = apply_filters( 'pvc_post_views_shortcode_atts', $atts, $args, $defaults ); 56 $period = isset( $atts['period'] ) ? sanitize_key( $atts['period'] ) : sanitize_key( $defaults['period'] ); 56 $atts = shortcode_atts( $defaults, $raw_args ); 57 $atts = apply_filters( 'pvc_post_views_shortcode_atts', $atts, $raw_args, $defaults ); 58 59 if ( ! is_array( $atts ) ) 60 $atts = []; 61 62 $type = isset( $atts['type'] ) && is_scalar( $atts['type'] ) ? sanitize_key( (string) $atts['type'] ) : ''; 63 $period = isset( $atts['period'] ) && is_scalar( $atts['period'] ) ? sanitize_key( (string) $atts['period'] ) : ''; 64 $atts['type'] = $type; 65 $atts['period'] = $period; 66 $format_present = array_key_exists( 'format', $atts ) && $atts['format'] !== null; 67 $post_id = isset( $atts['id'] ) && is_scalar( $atts['id'] ) && ctype_digit( (string) $atts['id'] ) ? (int) $atts['id'] : 0; 68 $atts['id'] = $post_id; 57 69 58 70 // default type? 59 if ( $atts['type'] === 'post' ) 60 $views = function_exists( 'pvc_post_views' ) ? pvc_post_views( $atts['id'], false, $period ) : 0; 61 62 return apply_filters( 'pvc_post_views_shortcode', $views, $atts ); 71 if ( $type === 'post' && $post_id > 0 && get_post( $post_id ) instanceof WP_Post ) { 72 $render_args = []; 73 74 if ( $format_present ) 75 $render_args['format'] = $atts['format']; 76 77 $html = function_exists( 'pvc_post_views' ) ? pvc_post_views( $post_id, false, $period, $render_args ) : ''; 78 } 79 80 return apply_filters( 'pvc_post_views_shortcode', $html, $atts ); 81 } 82 83 /** 84 * Render a complete custom metric template without parsing it as a shortcode. 85 * 86 * %%views%% renders the count and %%icon%% the counter icon. The icon is 87 * placed by the template alone and is not a metric, so a template without 88 * %%views%% still renders nothing. 89 * 90 * @param string $format Template HTML. 91 * @param int $content_id Content ID. 92 * @param string $content_type Content type. 93 * @param string $period Display period. 94 * @param callable $views_renderer Views token renderer. It receives whether the template has visible words of its own, so the count can leave out its hidden label. 95 * @param callable|null $icon_renderer Icon token renderer; null uses the counter icon without a content-type icon filter. 96 * @return string 97 */ 98 public function render_template( $format, $content_id, $content_type, $period, $views_renderer, $icon_renderer = null ) { 99 if ( ! is_scalar( $format ) || ! is_callable( $views_renderer ) ) 100 return ''; 101 102 $tag_pattern = self::get_template_tag_pattern(); 103 $format = preg_replace_callback( 104 $tag_pattern, 105 static function ( $matches ) { 106 return preg_replace_callback( 107 '/(["\'])(.*?)\1/', 108 static function ( $attribute ) { 109 return $attribute[1] . str_replace( '>', '>', $attribute[2] ) . $attribute[1]; 110 }, 111 $matches[0] 112 ); 113 }, 114 (string) $format 115 ); 116 $format = wp_kses_post( $format ); 117 $parts = preg_split( $tag_pattern, $format, -1, PREG_SPLIT_DELIM_CAPTURE ); 118 $token_pattern = '/%%(views|icon)%%/'; 119 $metrics = self::get_template_text_metrics( $format ); 120 121 if ( empty( $metrics ) ) 122 return ''; 123 124 if ( ! is_callable( $icon_renderer ) ) { 125 $frontend = $this; 126 $icon_renderer = static function () use ( $frontend, $content_id, $content_type ) { 127 return $frontend->get_counter_icon( 'views', $content_id, $content_type ); 128 }; 129 } 130 131 // A template that says "Views:" or "reads" itself already gives the count 132 // its context, and a hidden label would make a screen reader announce it 133 // twice. Only visible letters count: tokens, tags and attributes do not. 134 $text = ''; 135 136 foreach ( $parts as $index => $part ) { 137 if ( $index % 2 === 0 ) 138 $text .= preg_replace( $token_pattern, ' ', $part ); 139 } 140 141 $has_text = preg_match( '/\p{L}/u', html_entity_decode( $text, ENT_QUOTES, 'UTF-8' ) ) === 1; 142 143 // the icon is resolved only when the template places it, so its filters 144 // never run for a template without %%icon%% 145 $fragments = [ 'views' => (string) call_user_func( $views_renderer, $has_text ) ]; 146 147 foreach ( $parts as $index => $part ) { 148 if ( $index % 2 === 0 ) { 149 $parts[$index] = preg_replace_callback( 150 $token_pattern, 151 static function ( $matches ) use ( &$fragments, $icon_renderer ) { 152 // the template owns the spacing around the icon 153 if ( ! isset( $fragments[$matches[1]] ) ) 154 $fragments[$matches[1]] = rtrim( (string) call_user_func( $icon_renderer ) ); 155 156 return $fragments[$matches[1]]; 157 }, 158 $part 159 ); 160 } 161 } 162 163 $class = 'pvc-custom-format content-' . $content_type . ' ' . $content_type . '-' . $content_id . ' entry-meta'; 164 $html = '<div class="' . esc_attr( $class ) . '" data-pvc-type="' . esc_attr( $content_type ) . '" data-pvc-id="' . esc_attr( $content_id ) . '" data-pvc-period="' . esc_attr( $period ) . '">' . implode( '', $parts ) . '</div>'; 165 $html = apply_filters( 'pvc_frontend_template_html', $html, $format, $content_id, $content_type, $period, $metrics ); 166 167 return wp_kses( $html, Post_Views_Counter()->functions->get_counter_allowed_html() ); 168 } 169 170 /** 171 * Get the metric tokens present in the text parts of a sanitized template. 172 * 173 * Tokens in HTML attributes are not rendered and therefore are not metrics. 174 * 175 * @param string $format Sanitized template HTML. 176 * @return array 177 */ 178 public static function get_template_text_metrics( $format ) { 179 if ( ! is_scalar( $format ) ) 180 return []; 181 182 $parts = preg_split( self::get_template_tag_pattern(), (string) $format, -1, PREG_SPLIT_DELIM_CAPTURE ); 183 $metrics = []; 184 $token_pattern = '/%%(views)%%/'; 185 186 foreach ( $parts as $index => $part ) { 187 if ( $index % 2 !== 0 || preg_match_all( $token_pattern, $part, $matches ) === false ) 188 continue; 189 190 foreach ( $matches[1] as $metric ) { 191 if ( ! in_array( $metric, $metrics, true ) ) 192 $metrics[] = $metric; 193 } 194 } 195 196 return $metrics; 197 } 198 199 /** 200 * Get the HTML-tag pattern used to separate rendered text nodes. 201 * 202 * @return string 203 */ 204 private static function get_template_tag_pattern() { 205 return '/(<(?:"[^"]*"|\'[^\']*\'|[^\'">])*>)/'; 206 } 207 208 /** 209 * Get the validated and translated saved frontend template. 210 * 211 * @return string 212 */ 213 public function get_frontend_template() { 214 $pvc = Post_Views_Counter(); 215 $default = $pvc->defaults['display']['frontend_template']; 216 $source = isset( $pvc->options['display']['frontend_template'] ) && is_scalar( $pvc->options['display']['frontend_template'] ) ? (string) $pvc->options['display']['frontend_template'] : $default; 217 218 if ( function_exists( 'icl_t' ) ) { 219 $translated = icl_t( 'Post Views Counter', 'Frontend Template', $source ); 220 $source = is_scalar( $translated ) ? (string) $translated : $source; 221 } 222 223 return wp_kses_post( $source ); 224 } 225 226 /** 227 * Get the counter icon HTML for a metric. 228 * 229 * The icon is a CSS-masked glyph painted on an empty span, so the counter 230 * never loads the Dashicons font. Returning a class from 231 * 'pvc_counter_icon_class' replaces our glyph with that class instead; the 232 * stored 'icon_class' setting no longer takes part in rendering. 233 * 234 * @param string $metric Metric name; always 'views'. 235 * @param int $content_id Content ID. 236 * @param string $content_type Content type. 237 * @param string $icon_filter Metric-specific filter applied to the icon HTML. 238 * @return string 239 */ 240 public function get_counter_icon( $metric = 'views', $content_id = 0, $content_type = 'post', $icon_filter = '' ) { 241 $metric = 'views'; 242 $content_id = (int) $content_id; 243 $content_type = sanitize_key( (string) $content_type ); 244 245 // a custom class is the only supported way to replace the built-in glyph 246 $class = apply_filters( 'pvc_counter_icon_class', '', $metric, $content_id, $content_type ); 247 $class = is_scalar( $class ) ? Post_Views_Counter()->functions->sanitize_html_class_list( (string) $class ) : ''; 248 249 if ( $class !== '' ) 250 $default = '<span class="pvc-icon pvc-icon-custom ' . esc_attr( $class ) . '" aria-hidden="true"></span> '; 251 else 252 $default = '<span class="pvc-icon" aria-hidden="true"></span> '; 253 254 // the released metric-specific filters keep their markup-level authority 255 if ( is_string( $icon_filter ) && $icon_filter !== '' ) { 256 $icon = apply_filters( $icon_filter, $default, $content_id, $content_type ); 257 $icon = is_scalar( $icon ) ? (string) $icon : ''; 258 } else 259 $icon = $default; 260 261 $icon = apply_filters( 'pvc_counter_icon', $icon, $metric, $content_id, $content_type ); 262 263 return is_scalar( $icon ) ? (string) $icon : ''; 264 } 265 266 /** 267 * Render a single metric target. 268 * 269 * The single place a Views target is built, for every content type and render 270 * path. Preset roots may be divs; custom tokens are spans. Each target carries 271 * its loading/data identity and contains its own count element so current and 272 * legacy extension loaders can consume it. 273 * 274 * @param string $metric Metric name; only 'views' is rendered. 275 * @param int $content_id Content ID. 276 * @param string $content_type Content type. 277 * @param string $period Display period. 278 * @param array $args Optional per-caller overrides. 279 * @param array|null $resolved Resolved value, label and icon output. 280 * @return string 281 */ 282 public function render_metric_span( $metric, $content_id, $content_type, $period, $args = [], &$resolved = null ) { 283 $resolved = [ 'value' => null, 'label' => '', 'icon' => '' ]; 284 285 if ( $metric !== 'views' ) 286 return ''; 287 288 $options = Post_Views_Counter()->options['display']; 289 $content_id = (int) $content_id; 290 $content_type = sanitize_key( (string) $content_type ); 291 $period = sanitize_key( (string) $period ); 292 $supplied = is_array( $args ) ? $args : []; 293 294 $args = array_merge( 295 [ 296 'base_class' => 'post-views content-' . $content_type . ' ' . $content_type . '-' . $content_id . ' entry-meta', 297 'class_filter' => 'pvc_post_views_class', 298 'label_filter' => 'pvc_post_views_label', 299 'icon_filter' => 'pvc_post_views_icon', 300 'html_filter' => '', 301 'number_format_filter' => 'pvc_post_views_number_format', 302 'wpml_context' => 'Post Views Counter', 303 'wpml_name' => 'Post Views Label', 304 'wpml_fallbacks' => [], 305 'inline_icon' => false, 306 'force_sr_label' => false, 307 // a custom format with words of its own needs no label, visible or hidden 308 'omit_label' => false, 309 // null follows the dynamic_loading option; false forces a static span for 310 // content that is not a dynamic target, such as site-wide totals 311 'dynamic' => null, 312 // a pre-resolved icon, so a container that already rendered one does not 313 // fire the icon filter a second time 314 'icon' => null, 315 // an explicit label bypasses the option and WPML lookup entirely 316 'label' => null, 317 // preset output uses a div root; custom tokens use spans 318 'tag' => 'span', 319 'before' => '', 320 'after' => '' 321 ], 322 $supplied 323 ); 324 325 // resolve the value 326 if ( array_key_exists( 'value', $supplied ) ) 327 $views = $supplied['value']; 328 else { 329 $getter = 'pvc_get_' . $content_type . '_views'; 330 $views = function_exists( $getter ) ? call_user_func( $getter, $content_id, $period ) : 0; 331 } 332 333 $value = ! empty( $options['use_format'] ) ? number_format_i18n( $views ) : $views; 334 335 if ( $args['number_format_filter'] !== '' ) 336 $value = apply_filters( $args['number_format_filter'], $value, $content_id, $content_type, $period ); 337 338 // resolve the label 339 $raw_label = isset( $options['label'] ) && is_scalar( $options['label'] ) ? (string) $options['label'] : 'Views:'; 340 $label_supplied = array_key_exists( 'label', $supplied ) && is_scalar( $supplied['label'] ); 341 $label_default = $label_supplied ? (string) $supplied['label'] : $raw_label; 342 343 if ( ! $label_supplied && function_exists( 'icl_t' ) ) { 344 $translated = icl_t( $args['wpml_context'], $args['wpml_name'], $raw_label ); 345 $label_default = is_scalar( $translated ) ? (string) $translated : $raw_label; 346 347 // read-fallback: honor the legacy per-content-type string slots for one release 348 if ( $label_default === $raw_label && is_array( $args['wpml_fallbacks'] ) ) { 349 foreach ( $args['wpml_fallbacks'] as $fallback ) { 350 if ( ! is_array( $fallback ) || count( $fallback ) < 2 ) 351 continue; 352 353 $candidate = icl_t( $fallback[0], $fallback[1], $raw_label ); 354 355 if ( is_scalar( $candidate ) && (string) $candidate !== $raw_label ) { 356 $label_default = (string) $candidate; 357 358 break; 359 } 360 } 361 } 362 } 363 364 $label = apply_filters( $args['label_filter'], $label_default, $content_id, $content_type ); 365 $label = is_scalar( $label ) ? (string) $label : ''; 366 $metric_label = $label !== '' ? $label : __( 'Views:', 'post-views-counter' ); 367 368 // build the class string 369 $class = apply_filters( $args['class_filter'], $args['base_class'], $content_id, $content_type ); 370 $class = is_scalar( $class ) ? (string) $class : $args['base_class']; 371 $dynamic = $args['dynamic'] === null ? ! empty( $options['dynamic_loading'] ) : (bool) $args['dynamic']; 372 $class .= $dynamic ? ' load-dynamic' : ' load-static'; 373 374 $icon = is_string( $args['icon'] ) ? $args['icon'] : $this->get_counter_icon( 'views', $content_id, $content_type, $args['icon_filter'] ); 375 $show_icon = ! empty( $options['display_style']['icon'] ) && ! empty( $args['inline_icon'] ); 376 $show_text = ! empty( $options['display_style']['text'] ) && empty( $args['force_sr_label'] ); 377 378 if ( ! empty( $args['omit_label'] ) ) 379 $label_html = ''; 380 elseif ( $show_text ) 381 $label_html = '<span class="post-views-label pvc-label">' . esc_html( $label ) . '</span> '; 382 else 383 $label_html = '<span class="screen-reader-text pvc-metric-label pvc-label">' . esc_html( $metric_label ) . '</span> '; 384 385 $tag = $args['tag'] === 'div' ? 'div' : 'span'; 386 $before = is_scalar( $args['before'] ) ? (string) $args['before'] : ''; 387 $after = is_scalar( $args['after'] ) ? (string) $args['after'] : ''; 388 $html = '<' . $tag . ' class="' . esc_attr( $class ) . '" data-pvc-metric="views" data-pvc-type="' . esc_attr( $content_type ) . '" data-pvc-id="' . esc_attr( $content_id ) . '" data-pvc-period="' . esc_attr( $period ) . '"' 389 . ' data-pvc-server-formatted="true">' 390 . $before 391 . ( $show_icon ? $icon : '' ) 392 . $label_html 393 . '<span class="post-views-count pvc-count">' . wp_kses_post( $value ) . '</span>' 394 . $after 395 . '</' . $tag . '>'; 396 397 // report the resolved parts so a caller filtering at container level can 398 // pass the same arguments without re-running the value and label filters 399 $resolved = [ 'value' => $value, 'label' => $label, 'icon' => $icon ]; 400 401 if ( is_string( $args['html_filter'] ) && $args['html_filter'] !== '' ) { 402 $html = apply_filters( $args['html_filter'], $html, $content_id, $value, $label, $icon, $content_type, $period ); 403 $html = is_scalar( $html ) ? (string) $html : ''; 404 } 405 406 return $html; 407 } 408 409 /** 410 * Render the unified counter container. 411 * 412 * Preserves the released post-views root as the Views target and adds one 413 * icon and the container classes, so context and object classes remain on 414 * the root once. 415 * 416 * @param array $metrics Metric names; only 'views' is rendered. 417 * @param int $content_id Content ID. 418 * @param string $content_type Content type. 419 * @param string $period Display period. 420 * @param array $args Optional; 'metric_args' holds the 'views' overrides. 421 * @param array|null $resolved_out Resolved values keyed by metric. 422 * @return string 423 */ 424 public function render_counter( $metrics, $content_id, $content_type, $period, $args = [], &$resolved_out = null ) { 425 $resolved_out = []; 426 $metrics = is_array( $metrics ) ? $metrics : [ $metrics ]; 427 428 if ( ! in_array( 'views', $metrics, true ) ) 429 return ''; 430 431 $content_id = (int) $content_id; 432 $content_type = sanitize_key( (string) $content_type ); 433 $period = sanitize_key( (string) $period ); 434 $args = is_array( $args ) ? $args : []; 435 $per_metric = isset( $args['metric_args'] ) && is_array( $args['metric_args'] ) ? $args['metric_args'] : []; 436 $root_args = isset( $per_metric['views'] ) && is_array( $per_metric['views'] ) ? $per_metric['views'] : []; 437 438 // One container, one icon. The released metric-specific icon filter still 439 // runs. Callers such as pvc_site_views() may pass a pre-resolved icon to 440 // preserve their per-call icon contract. 441 $icon_filter = isset( $root_args['icon_filter'] ) && is_string( $root_args['icon_filter'] ) ? $root_args['icon_filter'] : 'pvc_post_views_icon'; 442 $icon = isset( $root_args['icon'] ) && is_string( $root_args['icon'] ) 443 ? $root_args['icon'] 444 : $this->get_counter_icon( 'views', $content_id, $content_type, $icon_filter ); 445 446 // Every root keeps the released `.post-views` class. Two independent 447 // reasons, both load-bearing: 448 // 449 // 1. It is the released styling hook. The shipped 1.7.15 stylesheet is 450 // written entirely against `.post-views`, and a decade of theme and user 451 // CSS targets it. 452 // 2. Replacing the Core frontend script can leave only a legacy loader, 453 // which collects targets 454 // with getElementsByClassName( 'post-views' ). A dynamic count is held at 455 // `color: transparent` until JS adds `.loaded` or `.load-error`, so a root 456 // that loader never claims stays permanently invisible. 457 $root_base = isset( $root_args['base_class'] ) && is_scalar( $root_args['base_class'] ) 458 ? (string) $root_args['base_class'] 459 : 'post-views content-' . $content_type . ' ' . $content_type . '-' . $content_id . ' entry-meta'; 460 461 $root_args['base_class'] = trim( (string) $root_base ) . ' pvc-container pvc-views'; 462 $root_args['inline_icon'] = true; 463 $root_args['icon'] = $icon; 464 $root_args['tag'] = 'div'; 465 $html = $this->render_metric_span( 'views', $content_id, $content_type, $period, $root_args, $root_resolved ); 466 467 if ( $html === '' ) 468 return ''; 469 470 $html = apply_filters( 'pvc_counter_html', $html, [ 'views' ], $content_id, $content_type, $period ); 471 472 // hand back what the counter resolved to, so a caller applying its own 473 // complete-counter filter can report the displayed value 474 $resolved_out = [ 'views' => $root_resolved ]; 475 476 return is_scalar( $html ) ? (string) $html : ''; 63 477 } 64 478 … … 164 578 if ( (bool) apply_filters( 'pvc_display_views_count', $display ) === true ) { 165 579 $filter = apply_filters( 'pvc_shortcode_filter_hook', $pvc->options['display']['position'] ); 166 167 switch ( $filter ) { 168 case 'after': 169 $content = $content . do_shortcode( '[post-views]' ); 170 break; 171 172 case 'before': 173 $content = do_shortcode( '[post-views]' ) . $content; 580 $custom = isset( $pvc->options['display']['frontend_counter_metrics'] ) && $pvc->options['display']['frontend_counter_metrics'] === 'custom'; 581 $output = $custom ? $this->post_views_shortcode( [ 'format' => $this->get_frontend_template() ] ) : do_shortcode( '[post-views]' ); 582 583 switch ( $filter ) { 584 case 'after': 585 $content = $content . $output; 586 break; 587 588 case 'before': 589 $content = $output . $content; 174 590 break; 175 591 … … 203 619 // enable styles? 204 620 if ( (bool) apply_filters( 'pvc_enqueue_styles', true ) === true ) { 205 // load dashicons206 wp_enqueue_style( 'dashicons' );207 208 621 // load style 209 622 wp_enqueue_style( 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/css/frontend.css', [], $pvc->defaults['version'] ); … … 214 627 return; 215 628 629 $dynamic_loading = ! empty( $pvc->options['display']['dynamic_loading'] ); 630 216 631 // get countable post types 217 632 $post_types = (array) $pvc->options['general']['post_types_count']; 218 219 // whether to count this post type or not220 if ( empty( $post_types ) || ! is_singular( $post_types ) )221 return;222 223 // get current post id224 633 $post_id = (int) get_the_ID(); 225 226 // allow to run check post?227 if ( ! (bool) apply_filters( 'pvc_run_check_post', true, $post_id ) )228 return;229 230 // get counter mode231 634 $mode = $pvc->options['general']['counter_mode']; 232 233 // specific counter mode? 234 if ( in_array( $mode, [ 'js', 'rest_api' ], true) ) {635 $should_count = ! empty( $post_types ) && is_singular( $post_types ) && (bool) apply_filters( 'pvc_run_check_post', true, $post_id ); 636 637 if ( $dynamic_loading || ( $should_count && in_array( $mode, [ 'js', 'rest_api' ], true ) ) ) { 235 638 wp_enqueue_script( 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/js/frontend.js', [], $pvc->defaults['version'], false ); 236 639 … … 238 641 $args = [ 239 642 'mode' => $mode, 643 'countEnabled' => $should_count && in_array( $mode, [ 'js', 'rest_api' ], true ), 240 644 'postID' => $post_id, 241 645 'requestURL' => '', 646 'displayURL' => untrailingslashit( rest_url( 'post-views-counter/get-post-views' ) ), 242 647 'nonce' => '', 243 'dataStorage' => $pvc->options['general']['data_storage'],244 'multisite' => ( is_multisite() ? (int) get_current_blog_id() : false ),648 'dataStorage' => $pvc->options['general']['data_storage'], 649 'multisite' => ( is_multisite() ? (int) get_current_blog_id() : false ), 245 650 'path' => empty( COOKIEPATH ) || ! is_string( COOKIEPATH ) ? '/' : COOKIEPATH, 246 651 'domain' => empty( COOKIE_DOMAIN ) || ! is_string( COOKIE_DOMAIN ) ? '' : COOKIE_DOMAIN -
post-views-counter/tags/1.8.0/includes/class-functions.php
r3280246 r3734102 196 196 return $color; 197 197 } 198 199 /** 200 * Convert an RGB color to HSL. 201 * 202 * Deliberately dependency-free: the only consumer is the derived Visits 203 * color, which needs a hue rotation and nothing a perceptual color library 204 * would add. 205 * 206 * @param int $r Red channel, 0-255. 207 * @param int $g Green channel, 0-255. 208 * @param int $b Blue channel, 0-255. 209 * @return array Hue in degrees, saturation and lightness as 0-1 floats. 210 */ 211 public function rgb2hsl( $r, $g, $b ) { 212 $r = (int) $r / 255; 213 $g = (int) $g / 255; 214 $b = (int) $b / 255; 215 216 $max = max( $r, $g, $b ); 217 $min = min( $r, $g, $b ); 218 $delta = $max - $min; 219 $l = ( $max + $min ) / 2; 220 221 // gray has no hue and no saturation 222 if ( $delta == 0 ) 223 return [ 'h' => 0.0, 's' => 0.0, 'l' => (float) $l ]; 224 225 $s = $l > 0.5 ? $delta / ( 2 - $max - $min ) : $delta / ( $max + $min ); 226 227 if ( $max === $r ) 228 $h = fmod( ( $g - $b ) / $delta, 6 ); 229 elseif ( $max === $g ) 230 $h = ( $b - $r ) / $delta + 2; 231 else 232 $h = ( $r - $g ) / $delta + 4; 233 234 $h *= 60; 235 236 if ( $h < 0 ) 237 $h += 360; 238 239 return [ 'h' => (float) $h, 's' => (float) $s, 'l' => (float) $l ]; 240 } 241 242 /** 243 * Resolve one HSL channel back to its 0-1 RGB value. 244 * 245 * @param float $p Lower bound. 246 * @param float $q Upper bound. 247 * @param float $t Normalized hue offset. 248 * @return float 249 */ 250 private function hue2channel( $p, $q, $t ) { 251 if ( $t < 0 ) 252 $t += 1; 253 254 if ( $t > 1 ) 255 $t -= 1; 256 257 if ( $t < 1 / 6 ) 258 return $p + ( $q - $p ) * 6 * $t; 259 260 if ( $t < 1 / 2 ) 261 return $q; 262 263 if ( $t < 2 / 3 ) 264 return $p + ( $q - $p ) * ( 2 / 3 - $t ) * 6; 265 266 return $p; 267 } 268 269 /** 270 * Convert an HSL color to RGB. 271 * 272 * @param float $h Hue in degrees. 273 * @param float $s Saturation, 0-1. 274 * @param float $l Lightness, 0-1. 275 * @return array 276 */ 277 public function hsl2rgb( $h, $s, $l ) { 278 $h = fmod( (float) $h, 360 ); 279 280 if ( $h < 0 ) 281 $h += 360; 282 283 $h /= 360; 284 $s = min( max( (float) $s, 0 ), 1 ); 285 $l = min( max( (float) $l, 0 ), 1 ); 286 287 if ( $s == 0 ) { 288 $value = (int) round( $l * 255 ); 289 290 return [ 'r' => $value, 'g' => $value, 'b' => $value ]; 291 } 292 293 $q = $l < 0.5 ? $l * ( 1 + $s ) : $l + $s - $l * $s; 294 $p = 2 * $l - $q; 295 296 return [ 297 'r' => (int) round( $this->hue2channel( $p, $q, $h + 1 / 3 ) * 255 ), 298 'g' => (int) round( $this->hue2channel( $p, $q, $h ) * 255 ), 299 'b' => (int) round( $this->hue2channel( $p, $q, $h - 1 / 3 ) * 255 ) 300 ]; 301 } 302 303 /** 304 * Derive the secondary Visits color from the Views color. 305 * 306 * Color means metric everywhere PVC draws a chart, so Visits needs exactly 307 * one companion color to whatever the admin theme gives Views. Rotating the 308 * hue by a fixed 45 degrees, capping saturation and clamping lightness keeps 309 * the result distinguishable and legible on every supported admin scheme 310 * without carrying a perceptual-color dependency. The dashed line remains 311 * the authoritative non-color distinction. 312 * 313 * @param array|null $rgb Source Views color; the admin-theme color by default. 314 * @return array 315 */ 316 public function get_visits_color( $rgb = null ) { 317 // the historical Visits purple, used whenever the source is unusable 318 $fallback = [ 'r' => 116, 'g' => 72, 'b' => 157 ]; 319 320 if ( $rgb === null ) 321 $rgb = $this->get_colors(); 322 323 if ( ! is_array( $rgb ) ) 324 return $fallback; 325 326 $source = []; 327 328 foreach ( [ 'r', 'g', 'b' ] as $channel ) { 329 if ( ! isset( $rgb[$channel] ) || ! is_numeric( $rgb[$channel] ) ) 330 return $fallback; 331 332 $value = (int) $rgb[$channel]; 333 334 if ( $value < 0 || $value > 255 ) 335 return $fallback; 336 337 $source[$channel] = $value; 338 } 339 340 $hsl = $this->rgb2hsl( $source['r'], $source['g'], $source['b'] ); 341 342 if ( ! is_array( $hsl ) || ! isset( $hsl['h'], $hsl['s'], $hsl['l'] ) ) 343 return $fallback; 344 345 // rotate hue with wraparound, cap saturation, clamp lightness 346 $derived = $this->hsl2rgb( fmod( $hsl['h'] + 45, 360 ), min( $hsl['s'], 0.6 ), min( max( $hsl['l'], 0.35 ), 0.5 ) ); 347 348 if ( ! is_array( $derived ) || ! isset( $derived['r'], $derived['g'], $derived['b'] ) ) 349 return $fallback; 350 351 return $derived; 352 } 353 354 /** 355 * Get the canonical Chart.js dataset style for one metric. 356 * 357 * Views and Visits look the same wherever they are drawn: the dashboard 358 * charts, the column modal, and the extension-provided charts. Views uses the admin-theme color, Visits the color 359 * derived from it, and the line variant separates them a second time with a 360 * dash pattern so the two series stay distinguishable without color. 361 * 362 * @param string $metric Metric identifier, 'views' or 'visits'. 363 * @param string $type Chart type, 'line' or 'bar'. 364 * @param array $context Optional presentation context. Only 'fill' is read: 365 * true draws the filled one- or two-line presentation. 366 * @return array 367 */ 368 public function get_metric_dataset_style( $metric = 'views', $type = 'line', $context = [] ) { 369 $metric = $metric === 'visits' ? 'visits' : 'views'; 370 $type = $type === 'bar' ? 'bar' : 'line'; 371 $context = is_array( $context ) ? $context : []; 372 $context = [ 'fill' => ! empty( $context['fill'] ) ]; 373 374 $color = $metric === 'visits' ? $this->get_visits_color() : $this->get_colors(); 375 $rgb = $color['r'] . ',' . $color['g'] . ',' . $color['b']; 376 377 if ( $type === 'bar' ) { 378 // Only the ranked Views reports draw bars, one dataset per chart, so 379 // there is no Visits bar variant. borderDash is deliberately absent - 380 // the Chart.js bar element has no such property and silently ignores 381 // it. Bar geometry never reads the fill context. The 0.2 fill is 382 // legacy report bars. 383 $style = [ 384 'backgroundColor' => 'rgba(' . $rgb . ',0.2)', 385 'borderColor' => 'rgba(' . $rgb . ',1)', 386 'borderWidth' => 0, 387 'grouped' => false, 388 'categoryPercentage' => 0.9, 389 'barPercentage' => 0.9 390 ]; 391 } else { 392 // One unified line presentation for every PVC line chart: a 2-pixel 393 // rounded stroke, a 0.4 tension curve, and white points with a 394 // 2-pixel stroke in the series color. The area fill varies only when a 395 // caller explicitly requests the unfilled presentation. 396 $style = [ 397 'borderColor' => 'rgba(' . $rgb . ',1)', 398 'backgroundColor' => 'rgba(' . $rgb . ',' . ( $context['fill'] ? '0.1' : '0.15' ) . ')', 399 'borderWidth' => 2, 400 'borderCapStyle' => 'round', 401 'borderJoinStyle' => 'round', 402 'borderDash' => $metric === 'visits' ? [ 6, 4 ] : [], 403 'fill' => $context['fill'] ? 'origin' : false, 404 'tension' => 0.4, 405 'pointRadius' => 3, 406 'pointHoverRadius' => 5, 407 'pointBackgroundColor' => 'rgba(255,255,255,1)', 408 'pointBorderColor' => 'rgba(' . $rgb . ',1)', 409 'pointBorderWidth' => 2 410 ]; 411 } 412 413 // the context is additive; the first three arguments keep their meaning 414 return apply_filters( 'pvc_metric_dataset_style', $style, $metric, $type, $context ); 415 } 416 417 /** 418 * Attach locale-formatted tooltip values to Chart.js datasets. 419 * 420 * Tooltips print these strings, so they match the admin column, which 421 * formats with number_format_i18n(). Entities are decoded because Chart.js 422 * draws text on a canvas. A value that is not numeric stays null. 423 * 424 * @param array $chart Chart.js data object holding a datasets list. 425 * @return array 426 */ 427 public function format_chart_datasets( $chart ) { 428 if ( ! is_array( $chart ) || empty( $chart['datasets'] ) || ! is_array( $chart['datasets'] ) ) 429 return $chart; 430 431 foreach ( $chart['datasets'] as $index => $dataset ) { 432 if ( ! is_array( $dataset ) || ! isset( $dataset['data'] ) || ! is_array( $dataset['data'] ) ) 433 continue; 434 435 $chart['datasets'][$index]['formatted'] = array_map( static function ( $value ) { 436 return is_numeric( $value ) ? html_entity_decode( number_format_i18n( (float) $value ), ENT_QUOTES, 'UTF-8' ) : null; 437 }, $dataset['data'] ); 438 } 439 440 return $chart; 441 } 442 443 /** 444 * Get the allowed HTML for sanitizing rendered counter markup. 445 * 446 * wp_kses_post() strips inline SVG, which would silently empty the counter 447 * icon. This is the post allow-list plus the two elements the shared icon 448 * uses, so counter output can still be sanitized before it is echoed. 449 * 450 * @return array 451 */ 452 public function get_counter_allowed_html() { 453 $allowed = wp_kses_allowed_html( 'post' ); 454 455 // kses lowercases attribute names; the HTML parser maps viewbox back to 456 // viewBox for inline SVG, so the rendered icon is unaffected. 457 $allowed['svg'] = [ 458 'aria-hidden' => true, 459 'class' => true, 460 'fill' => true, 461 'focusable' => true, 462 'height' => true, 463 'role' => true, 464 'viewbox' => true, 465 'width' => true, 466 'xmlns' => true 467 ]; 468 $allowed['path'] = [ 469 'd' => true, 470 'fill' => true 471 ]; 472 473 return $allowed; 474 } 475 476 /** 477 * Sanitize a space-separated list of HTML classes. 478 * 479 * @param string $class Raw class list. 480 * @return string 481 */ 482 public function sanitize_html_class_list( $class ) { 483 if ( ! is_scalar( $class ) ) 484 return ''; 485 486 $classes = preg_split( '/\s+/', trim( (string) $class ) ); 487 $classes = array_filter( array_map( 'sanitize_html_class', is_array( $classes ) ? $classes : [] ) ); 488 489 return implode( ' ', array_unique( $classes ) ); 490 } 491 492 /** 493 * Get the shared inline bar-chart counter icon. 494 * 495 * The single source of the plugin's bar-chart glyph: the admin columns inline 496 * it and the admin menu icon is built from it. The frontend paints the same 497 * glyph through a CSS mask, so its path data is duplicated in the stylesheet 498 * and locked to this one by test. 499 * 500 * @return string 501 */ 502 public function get_counter_icon_svg() { 503 return '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3.5 15v6a1.5 1.5 0 0 0 3 0v-6a1.5 1.5 0 0 0-3 0Zm7-6v12a1.5 1.5 0 0 0 3 0V9a1.5 1.5 0 0 0-3 0Zm7-6v18a1.5 1.5 0 0 0 3 0V3a1.5 1.5 0 0 0-3 0Z" /></svg>'; 504 } 505 506 /** 507 * Get the counter icon as an admin menu icon. 508 * 509 * WordPress recolours a menu icon to the admin colour scheme only when it is 510 * a base64 SVG data URI, by rewriting its fill attributes. The literal fill is 511 * the default scheme's icon colour, so the icon is right before that script 512 * runs. 513 * 514 * @return string 515 */ 516 public function get_menu_icon_data_uri() { 517 $svg = str_replace( 'fill="currentColor"', 'fill="#a7aaad"', $this->get_counter_icon_svg() ); 518 519 return 'data:image/svg+xml;base64,' . base64_encode( $svg ); 520 } 198 521 } -
post-views-counter/tags/1.8.0/includes/class-import.php
r3647380 r3734102 295 295 296 296 // Preserve the pre-1.7.15 contract for filtered definitions that expose 297 // only the legacy Probadge/availability flag.297 // only the legacy premium badge/availability flag. 298 298 if ( ! empty( $definition['pro_only'] ) ) { 299 299 return class_exists( 'Post_Views_Counter_Pro' ); … … 1681 1681 * Rejects malformed values, zero dates, year zero and impossible calendar 1682 1682 * dates. This strict policy applies to Page Views Count source rows and to 1683 * the reported source date range; Statify row handling is unchanged (D8-8).1683 * the reported source date range; Statify row handling is unchanged. 1684 1684 * 1685 1685 * @param mixed $value Source date. -
post-views-counter/tags/1.8.0/includes/class-query.php
r3514398 r3734102 51 51 */ 52 52 public function extend_pre_query( $query ) { 53 $this->join_sql = ''; 54 $query->pvc_orderby = false; 55 $query->pvc_query = false; 56 $query->total_views = 0; 57 58 $orderby = isset( $query->query_vars['orderby'] ) ? $query->query_vars['orderby'] : ''; 59 $has_orderby = function( $metric ) use ( $orderby ) { 60 if ( is_array( $orderby ) ) 61 return array_key_exists( $metric, $orderby ); 62 63 return is_string( $orderby ) && preg_match( '/(?:^|\s)' . preg_quote( $metric, '/' ) . '(?:\s|$)/', $orderby ) === 1; 64 }; 65 $query->pvc_orderby = $has_orderby( 'post_views' ); 66 53 67 // skip empty sort order 54 68 if ( empty( $query->query_vars['orderby'] ) ) … … 253 267 254 268 // is it sorted by post views? 255 if ( ( $sql === '' && isset( $query->pvc_orderby ) && $query->pvc_orderby) || apply_filters( 'pvc_extend_post_object', false, $query ) === true )269 if ( ( $sql === '' && ! empty( $query->pvc_orderby ) ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) 256 270 $sql = ' AND pvc.type = 4'; 257 271 … … 260 274 global $wpdb; 261 275 262 $join .= " LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = " . $wpdb->prefix . "posts.ID" . $sql; 276 $content_sql = pvc_post_views_has_content_column() ? ' AND pvc.content = 0' : ''; 277 $join .= " LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = " . $wpdb->prefix . "posts.ID" . $content_sql . $sql; 263 278 264 279 $this->join_sql = $join; … … 280 295 public function posts_groupby( $groupby, $query ) { 281 296 // is it sorted by post views or views_query is used? 282 if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) &&$query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {297 if ( ! empty( $query->pvc_orderby ) || ! empty( $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) { 283 298 global $pagenow; 284 299 … … 334 349 335 350 // hide empty? 336 if ( ! isset( $query->query['views_query']['hide_empty'] ) || $query->query['views_query']['hide_empty'] === true ) 337 $groupby .= ' HAVING post_views > 0'; 351 $views_query = isset( $query->query['views_query'] ) ? $query->query['views_query'] : []; 352 353 if ( ! isset( $views_query['hide_empty'] ) || $views_query['hide_empty'] === true ) 354 $groupby .= ' HAVING SUM( COALESCE( pvc.count, 0 ) ) > 0'; 338 355 } 339 356 … … 349 366 */ 350 367 public function posts_orderby( $orderby, $query ) { 351 // is it sorted by post views? 352 if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) ) { 353 // get order 354 $order = strtoupper( (string) $query->get( 'order' ) ); 355 $org_orderby = $query->get( 'orderby' ); 356 357 if ( ! in_array( $order, [ 'ASC', 'DESC' ], true ) ) 358 $order = 'DESC'; 359 360 if ( is_array( $org_orderby ) && array_key_exists( 'post_views', $org_orderby ) ) { 361 $post_views_order = strtoupper( (string) $org_orderby['post_views'] ); 362 363 if ( in_array( $post_views_order, [ 'ASC', 'DESC' ], true ) ) 364 $order = $post_views_order; 365 } 366 367 $post_views_orderby = 'post_views ' . $order; 368 369 if ( ! is_string( $orderby ) || trim( $orderby ) === '' ) 370 $orderby = $post_views_orderby; 371 elseif ( preg_match( '/\bpost_views\b/i', $orderby ) !== 1 ) 372 $orderby = $post_views_orderby . ', ' . $orderby; 373 } 374 375 return $orderby; 368 global $wpdb; 369 370 if ( empty( $query->pvc_orderby ) ) 371 return $orderby; 372 373 $requested = $query->get( 'orderby' ); 374 $default_order = strtoupper( (string) $query->get( 'order' ) ); 375 376 if ( ! in_array( $default_order, [ 'ASC', 'DESC' ], true ) ) 377 $default_order = 'DESC'; 378 379 $tokens = $this->get_metric_orderby_tokens( $requested, $default_order ); 380 $nonmetric = $this->split_top_level_orderby( $orderby ); 381 $translated = []; 382 383 foreach ( $tokens as $token ) { 384 if ( $token['metric'] === 'post_views' && ! empty( $query->pvc_orderby ) ) 385 $translated[] = 'SUM( COALESCE( pvc.count, 0 ) ) ' . $token['order'] . ( isset( $query->pvc_admin_column_sort ) && $query->pvc_admin_column_sort === 'views' ? ', ' . $wpdb->posts . '.ID ASC' : '' ); 386 elseif ( $this->did_wordpress_orderby_token_emit_clause( $token['metric'], $query ) && ! empty( $nonmetric ) ) 387 $translated[] = array_shift( $nonmetric ); 388 } 389 390 return implode( ', ', array_merge( $translated, $nonmetric ) ); 391 } 392 393 /** 394 * Split rendered ORDER BY SQL at commas outside function calls and quoted 395 * strings. WordPress uses FIELD( ... ) for the inclusion-order tokens. 396 * 397 * @param mixed $orderby Rendered ORDER BY SQL. 398 * @return array 399 */ 400 private function split_top_level_orderby( $orderby ) { 401 if ( ! is_string( $orderby ) || trim( $orderby ) === '' ) 402 return []; 403 404 $clauses = []; 405 $start = 0; 406 $depth = 0; 407 $quote = ''; 408 $length = strlen( $orderby ); 409 410 for ( $index = 0; $index < $length; $index++ ) { 411 $character = $orderby[$index]; 412 413 if ( $quote !== '' ) { 414 if ( $character === $quote && ( $index === 0 || $orderby[$index - 1] !== '\\' ) ) 415 $quote = ''; 416 continue; 417 } 418 419 if ( $character === "'" || $character === '"' || $character === '`' ) 420 $quote = $character; 421 elseif ( $character === '(' ) 422 $depth++; 423 elseif ( $character === ')' && $depth > 0 ) 424 $depth--; 425 elseif ( $character === ',' && $depth === 0 ) { 426 $clause = trim( substr( $orderby, $start, $index - $start ) ); 427 if ( $clause !== '' ) 428 $clauses[] = $clause; 429 $start = $index + 1; 430 } 431 } 432 433 $clause = trim( substr( $orderby, $start ) ); 434 if ( $clause !== '' ) 435 $clauses[] = $clause; 436 437 return $clauses; 438 } 439 440 /** 441 * Check whether a requested token emitted one rendered WordPress clause. 442 * 443 * This mirrors the supported WP 6.3 parse_orderby() branches. Requested 444 * inclusion and meta tokens are not necessarily rendered, so they must not 445 * consume a later clause while metric ordering is reconstructed. 446 * 447 * @param string $token Requested orderby token. 448 * @param object $query WP_Query instance. 449 * @return bool 450 */ 451 private function did_wordpress_orderby_token_emit_clause( $token, $query ) { 452 $token = (string) $token; 453 $meta_clauses = is_object( $query->meta_query ) && method_exists( $query->meta_query, 'get_clauses' ) ? $query->meta_query->get_clauses() : []; 454 $meta_clauses = is_array( $meta_clauses ) ? $meta_clauses : []; 455 $primary_meta_clause = empty( $meta_clauses ) ? [] : reset( $meta_clauses ); 456 $primary_meta_key = is_array( $primary_meta_clause ) && ! empty( $primary_meta_clause['key'] ) ? (string) $primary_meta_clause['key'] : ''; 457 458 switch ( $token ) { 459 // WP_Query::parse_orderby() renders these direct fields and aliases. 460 case 'post_name': 461 case 'post_author': 462 case 'post_date': 463 case 'post_title': 464 case 'post_modified': 465 case 'post_parent': 466 case 'post_type': 467 case 'name': 468 case 'author': 469 case 'date': 470 case 'title': 471 case 'modified': 472 case 'parent': 473 case 'type': 474 case 'ID': 475 case 'menu_order': 476 case 'comment_count': 477 case 'rand': 478 return true; 479 480 case 'post__in': 481 return ! empty( $query->get( 'post__in' ) ); 482 483 case 'post_name__in': 484 return ! empty( $query->get( 'post_name__in' ) ); 485 486 case 'post_parent__in': 487 return ! empty( $query->get( 'post_parent__in' ) ); 488 489 case 'meta_value': 490 case 'meta_value_num': 491 return ! empty( $meta_clauses ); 492 493 case 'relevance': 494 // Core only emits search relevance for the standalone string token. 495 return ! empty( $query->get( 's' ) ) && $query->get( 'orderby' ) === 'relevance'; 496 } 497 498 if ( $primary_meta_key !== '' && $token === $primary_meta_key ) 499 return true; 500 501 if ( array_key_exists( $token, $meta_clauses ) ) 502 return true; 503 504 return preg_match( '/^RAND\([0-9]+\)$/i', $token ) === 1; 505 } 506 507 /** 508 * Preserve metric tokens at their original WP_Query orderby positions. 509 * 510 * @param mixed $orderby Requested orderby value. 511 * @param string $default_order Validated query-wide direction. 512 * @return array 513 */ 514 private function get_metric_orderby_tokens( $orderby, $default_order ) { 515 $tokens = []; 516 517 if ( is_array( $orderby ) ) { 518 foreach ( $orderby as $key => $direction ) { 519 // a non-scalar direction (orderby[title][]=x) takes the default order 520 $order = is_scalar( $direction ) ? strtoupper( (string) $direction ) : $default_order; 521 $tokens[] = [ 522 'metric' => (string) $key, 523 'order' => in_array( $order, [ 'ASC', 'DESC' ], true ) ? $order : $default_order 524 ]; 525 } 526 527 return $tokens; 528 } 529 530 $parts = preg_split( '/\s+/', trim( (string) $orderby ) ); 531 532 for ( $index = 0; $index < count( $parts ); $index++ ) { 533 $order = $default_order; 534 535 if ( isset( $parts[$index + 1] ) && in_array( strtoupper( $parts[$index + 1] ), [ 'ASC', 'DESC' ], true ) ) 536 $order = strtoupper( $parts[++$index] ); 537 538 $tokens[] = [ 'metric' => $parts[$index], 'order' => $order ]; 539 } 540 541 return $tokens; 376 542 } 377 543 … … 384 550 */ 385 551 public function posts_distinct( $distinct, $query ) { 386 if ( ( ( isset( $query->pvc_groupby ) && $query->pvc_groupby ) || ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) && ( strpos( $distinct, 'DISTINCT' ) === false ))552 if ( ( ! empty( $query->pvc_groupby ) || ! empty( $query->pvc_orderby ) || ! empty( $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) && strpos( $distinct, 'DISTINCT' ) === false ) 387 553 $distinct = $distinct . ' DISTINCT '; 388 554 … … 398 564 */ 399 565 public function posts_fields( $fields, $query ) { 400 if ( ( ! isset( $query->query['fields'] ) || $query->query['fields'] === '' || $query->query['fields'] === 'all' ) && ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) ) 401 $fields = $fields . ', SUM( COALESCE( pvc.count, 0 ) ) AS post_views'; 566 if ( ! isset( $query->query['fields'] ) || $query->query['fields'] === '' || $query->query['fields'] === 'all' ) { 567 if ( ! empty( $query->pvc_orderby ) || ! empty( $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) 568 $fields .= ', SUM( COALESCE( pvc.count, 0 ) ) AS post_views'; 569 } 402 570 403 571 return $fields; … … 495 663 */ 496 664 public function the_posts( $posts, $query ) { 497 if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) &&$query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {665 if ( ! empty( $query->pvc_orderby ) || ! empty( $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) { 498 666 $sum = 0; 499 667 … … 501 669 if ( ! empty( $posts ) ) { 502 670 foreach ( $posts as $post ) { 503 if ( ! empty( $post->post_views ) )671 if ( is_object( $post ) && ! empty( $post->post_views ) ) 504 672 $sum += (int) $post->post_views; 505 673 } -
post-views-counter/tags/1.8.0/includes/class-settings-api.php
r3640258 r3734102 742 742 'target' => ! empty( $condition['target'] ) ? sanitize_text_field( $condition['target'] ) : '', 743 743 'container' => ! empty( $condition['container'] ) ? sanitize_text_field( $condition['container'] ) : '', 744 // Opt-in only: a conditionally disabled checkbox or radio target is 745 // cleared before it is disabled. Ordinary disabled controls keep 746 // their value. 747 'clear_on_disable' => ! empty( $condition['clear_on_disable'] ), 744 748 ]; 745 749 } … … 1054 1058 } 1055 1059 1056 return stripslashes_deep( $value );1060 return $value; 1057 1061 } 1058 1062 -
post-views-counter/tags/1.8.0/includes/class-settings-display.php
r3470602 r3734102 68 68 // get post types 69 69 $post_types = $this->pvc->functions->get_post_types(); 70 $frontend_template = isset( $this->pvc->options['display']['frontend_template'] ) && is_scalar( $this->pvc->options['display']['frontend_template'] ) ? (string) $this->pvc->options['display']['frontend_template'] : $this->pvc->defaults['display']['frontend_template']; 71 $frontend_template = wp_kses_post( $frontend_template ); 72 $template_notice = empty( Post_Views_Counter_Frontend::get_template_text_metrics( $frontend_template ) ) ? ' <span class="pvc-frontend-template-empty-notice">' . esc_html__( 'This custom format currently displays no counter.', 'post-views-counter' ) . '</span>' : ''; 70 73 71 74 // user groups 75 // Rendering order only. Guests first, then the two mutually exclusive 76 // logged-in audiences. The stored keys are unchanged. 72 77 $groups = [ 73 ' users' => __( 'logged in users', 'post-views-counter' ),74 ' guests' => __( 'guests', 'post-views-counter' ),75 'roles' => __( ' selected user roles', 'post-views-counter' )78 'guests' => __( 'Guests', 'post-views-counter' ), 79 'users' => __( 'All logged-in users', 'post-views-counter' ), 80 'roles' => __( 'Selected user roles', 'post-views-counter' ) 76 81 ]; 77 82 … … 80 85 81 86 return [ 87 'frontend_counter_metrics' => [ 88 'tab' => 'display', 89 'title' => __( 'Display Format', 'post-views-counter' ), 90 'section' => 'post_views_counter_display_appearance', 91 'type' => 'select', 92 'html_id' => 'pvc-frontend-counter-metrics', 93 /* translators: %s: [post-views] shortcode */ 94 'description' => sprintf( __( 'Choose the format of the counter inserted automatically on the frontend. A manually placed %s shortcode keeps the Views format.', 'post-views-counter' ), '<code>[post-views]</code>' ), 95 'validate' => [ $this, 'validate_frontend_counter_metrics' ], 96 'options' => [ 97 'views' => __( 'Views', 'post-views-counter' ), 98 'custom' => __( 'Custom format', 'post-views-counter' ) 99 ] 100 ], 101 'frontend_template' => [ 102 'tab' => 'display', 103 'title' => __( 'Custom Format', 'post-views-counter' ), 104 'section' => 'post_views_counter_display_appearance', 105 'type' => 'input', 106 'html_id' => 'pvc-frontend-template', 107 'before_field' => '<label class="screen-reader-text" for="pvc-frontend-template">' . esc_html__( 'Custom Format', 'post-views-counter' ) . '</label>', 108 /* translators: 1: views token, 2: icon token */ 109 'description' => sprintf( __( 'Build the counter with %1$s (the view count) and %2$s (the counter icon). Safe HTML is allowed. A format without %1$s displays nothing.', 'post-views-counter' ), '<code>%%views%%</code>', '<code>%%icon%%</code>' ) . $template_notice, 110 'subclass' => 'regular-text', 111 'validate' => [ $this, 'validate_frontend_template' ], 112 'reset' => [ $this, 'reset_frontend_template' ], 113 'logic' => [ 114 'field' => 'pvc-frontend-counter-metrics', 115 'operator' => 'is', 116 'value' => 'custom' 117 ], 118 'animation' => 'slide' 119 ], 82 120 'label' => [ 83 121 'tab' => 'display', … … 89 127 'subclass' => 'regular-text', 90 128 'validate' => [ $this, 'validate_label' ], 91 'reset' => [ $this, 'reset_label' ] 129 'reset' => [ $this, 'reset_label' ], 130 'logic' => [ 131 [ 132 'field' => 'pvc-frontend-counter-metrics', 133 'operator' => 'isnot', 134 'value' => 'custom' 135 ] 136 ], 137 'animation' => 'slide' 92 138 ], 93 139 'display_period' => [ … … 117 163 'icon' => __( 'Icon', 'post-views-counter' ), 118 164 'text' => __( 'Label', 'post-views-counter' ) 119 ] 165 ], 166 // a custom format places the icon itself with %%icon%%, so the 167 // preset's icon and label choices do not apply to it 168 'logic' => [ 169 'field' => 'pvc-frontend-counter-metrics', 170 'operator' => 'isnot', 171 'value' => 'custom' 172 ], 173 'animation' => 'slide' 120 174 ], 121 175 'icon_class' => [ … … 133 187 ], 134 188 'animation' => 'slide', 135 'description' => sprintf( __( 'Enter the CSS class for the views icon. Any Dashicons class is supported.', 'post-views-counter' ), 'https://developer.wordpress.org/resource/dashicons/' ), 189 // Retired: the counter icon is painted by a CSS mask and no longer uses 190 // an icon font. The stored value is kept untouched for a possible later 191 // use, but takes no part in rendering; 'pvc_counter_icon_class' is the 192 // supported way to supply a custom icon. skip_saving is what carries the 193 // stored value through a save of this tab, since an unrendered field 194 // submits nothing and would otherwise be reset to the default. 195 'skip_rendering' => true, 196 'skip_saving' => true, 197 'description' => __( 'Retired. The counter icon no longer uses the Dashicons font. Use the pvc_counter_icon_class filter to supply a custom icon class.', 'post-views-counter' ), 136 198 'subclass' => 'regular-text' 137 199 ], … … 163 225 'type' => 'boolean', 164 226 'description' => '', 165 'label' => __( 'Allow editing the view count on the post edit screen.', 'post-views-counter' )227 'label' => __( 'Allow manual editing of the Views total.', 'post-views-counter' ) 166 228 ], 167 229 'dynamic_loading' => [ … … 255 317 'section' => 'post_views_counter_display_visibility', 256 318 'type' => 'checkbox', 257 'description' => __( 'Hide the view counter for selected visitor groups.', 'post-views-counter' ),319 'description' => __( 'Hide the automatically inserted counter from the selected visitor groups. Note: selecting both "Guests" and "All logged-in users" hides the automatic counter from everyone.', 'post-views-counter' ), 258 320 'options' => $groups, 259 321 'name' => 'post_views_counter_settings_display[restrict_display][groups]', 260 322 'value' => $this->pvc->options['display']['restrict_display']['groups'], 261 323 'validate' => [ $this, 'validate_restrict_display_groups' ], 324 // "Selected user roles" is unreachable while every logged-in user is 325 // already hidden, so the option is cleared and disabled in that state. 326 'logic' => [ 327 [ 328 'field' => 'restrict_display_groups', 329 'operator' => 'containsnot', 330 'value' => 'users', 331 'scope' => 'option', 332 'action' => 'enable', 333 'target' => '#pvc-display-restrict-display-groups-roles', 334 'clear_on_disable' => true 335 ] 336 ], 262 337 ], 263 338 'restrict_display_roles' => [ … … 266 341 'section' => 'post_views_counter_display_visibility', 267 342 'type' => 'checkbox', 268 'description' => __( 'Hide the view counter forselected user roles.', 'post-views-counter' ),343 'description' => __( 'Hide the automatically inserted counter from the selected user roles.', 'post-views-counter' ), 269 344 'options' => $user_roles, 270 345 'name' => 'post_views_counter_settings_display[restrict_display][roles]', … … 325 400 if ( function_exists( 'icl_register_string' ) ) 326 401 icl_register_string( 'Post Views Counter', 'Post Views Label', $default ); 402 403 return $default; 404 } 405 406 /** 407 * Validate the metric selected for automatic frontend injection. 408 * 409 * @param mixed $input Submitted value. 410 * @param array $field Field definition. 411 * @return string 412 */ 413 public function validate_frontend_counter_metrics( $input, $field ) { 414 $input = is_scalar( $input ) ? sanitize_key( (string) $input ) : ''; 415 416 return in_array( $input, [ 'views', 'custom' ], true ) ? $input : 'views'; 417 } 418 419 /** 420 * Validate and register the custom frontend template. 421 * 422 * @param mixed $input Submitted value. 423 * @param array $field Field definition. 424 * @return string 425 */ 426 public function validate_frontend_template( $input, $field ) { 427 if ( is_scalar( $input ) ) 428 $template = wp_kses_post( (string) $input ); 429 else { 430 $current = isset( $this->pvc->options['display']['frontend_template'] ) ? $this->pvc->options['display']['frontend_template'] : null; 431 $template = is_scalar( $current ) ? wp_kses_post( (string) $current ) : $this->pvc->defaults['display']['frontend_template']; 432 } 433 434 if ( function_exists( 'icl_register_string' ) ) 435 icl_register_string( 'Post Views Counter', 'Frontend Template', $template ); 436 437 return $template; 438 } 439 440 /** 441 * Restore and register the default custom frontend template. 442 * 443 * @param string $default Default value. 444 * @param array $field Field definition. 445 * @return string 446 */ 447 public function reset_frontend_template( $default, $field ) { 448 $default = wp_kses_post( (string) $default ); 449 450 if ( function_exists( 'icl_register_string' ) ) 451 icl_register_string( 'Post Views Counter', 'Frontend Template', $default ); 327 452 328 453 return $default; … … 407 532 } 408 533 409 return array_unique( $groups ); 534 $groups = array_unique( $groups ); 535 536 // "All logged-in users" and "Selected user roles" are alternatives: the role 537 // branch is unreachable while every logged-in user is already hidden. Drop 538 // the unreachable marker so a no-JavaScript submission cannot store a 539 // contradictory state. The separately stored role list is never touched. 540 if ( in_array( 'users', $groups, true ) ) 541 $groups = array_diff( $groups, [ 'roles' ] ); 542 543 return array_values( $groups ); 410 544 } 411 545 -
post-views-counter/tags/1.8.0/includes/class-settings-emails.php
r3556892 r3734102 618 618 619 619 /** 620 * Determine whether PVC Prois active.620 * Determine whether the extension plugin is active. 621 621 * 622 622 * @return bool -
post-views-counter/tags/1.8.0/includes/class-settings.php
r3537950 r3734102 681 681 // add parameters 682 682 $pages['post-views-counter']['type'] = 'page'; 683 $pages['post-views-counter']['icon'] = 'dashicons-chart-bar';683 $pages['post-views-counter']['icon'] = $pvc->functions->get_menu_icon_data_uri(); 684 684 $pages['post-views-counter']['position'] = '99.301'; 685 685 … … 938 938 // make sure we do not change anything in the settings 939 939 $input = $pvc->options['other']; 940 941 if ( $wpdb->query( 'TRUNCATE TABLE ' . $wpdb->prefix . 'post_views' ) ) 942 add_settings_error( 'reset_post_views', 'reset_post_views', __( 'All existing data deleted successfully.', 'post-views-counter' ), 'updated' ); 943 else 944 add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Error occurred. All existing data were not deleted.', 'post-views-counter' ), 'error' ); 940 $this->reset_views_data(); 945 941 // save general settings 946 942 } elseif ( isset( $_POST['save_post_views_counter_settings_general'] ) ) { … … 988 984 989 985 return $input; 986 } 987 988 /** 989 * Delete shared counter data under a Visit-state write fence. 990 * 991 * @return void 992 */ 993 private function reset_views_data() { 994 global $wpdb; 995 996 $pvc = Post_Views_Counter(); 997 $visits = $pvc->visits instanceof Post_Views_Counter_Visits ? $pvc->visits : null; 998 999 if ( function_exists( 'Post_Views_Counter_Pro' ) ) { 1000 $pro = Post_Views_Counter_Pro(); 1001 $pro_counter = isset( $pro->counter ) ? $pro->counter : null; 1002 1003 if ( ! is_object( $pro_counter ) || ! method_exists( $pro_counter, 'supports_queue_generation' ) || ! $pro_counter->supports_queue_generation() ) { 1004 add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Queued counts cannot be retired safely. Update or deactivate Post Views Counter Pro before retrying.', 'post-views-counter' ), 'error' ); 1005 return; 1006 } 1007 } 1008 1009 $reset_locked = $visits === null || $visits->begin_measurement_fence(); 1010 1011 if ( ! $reset_locked ) { 1012 add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Error occurred. All existing data were not deleted.', 'post-views-counter' ), 'error' ); 1013 return; 1014 } 1015 1016 $timestamp = time(); 1017 $entry = [ 'code' => 'completed', 'raw' => null ]; 1018 $completion = [ 'code' => 'completed', 'raw' => null ]; 1019 $result = 'failed'; 1020 $fence_result = [ 'unlocked' => false, 'flushed' => false ]; 1021 1022 try { 1023 if ( $visits !== null ) { 1024 $entry = $visits->enter_visit_reset_v0( $timestamp ); 1025 1026 if ( $entry['code'] !== 'completed' ) { 1027 $result = 'entry_failed'; 1028 } else { 1029 // The descriptor is inert while fenced and is drained exactly once by 1030 // the checked outermost unlock. 1031 $visits->defer_measurement_fence_work( [ 'type' => 'state_caches', 'retire_reads' => true ] ); 1032 } 1033 } 1034 1035 if ( $result !== 'entry_failed' && $wpdb->query( 'TRUNCATE TABLE ' . $wpdb->prefix . 'post_views' ) === false ) 1036 $result = 'truncate_failed'; 1037 1038 if ( $result === 'failed' && $visits !== null ) { 1039 $completion = $visits->complete_visit_reset_v0( $entry['raw'], $timestamp ); 1040 $result = $completion['code'] === 'completed' ? 'completed' : 'completion_failed'; 1041 } elseif ( $result === 'failed' ) 1042 $result = 'completed'; 1043 } finally { 1044 if ( $visits !== null ) 1045 $fence_result = $visits->end_measurement_fence(); 1046 } 1047 1048 if ( $visits !== null && ( empty( $fence_result['unlocked'] ) || empty( $fence_result['flushed'] ) ) ) 1049 $result = 'retirement_failed'; 1050 1051 // The failed unlock deliberately retains the SQL fence. Do not invoke a 1052 // translated admin notice (or any post-fence publication) until recovery 1053 // can release it; the version-zero state remains the durable failure signal. 1054 if ( $visits !== null && $visits->is_measurement_fence_active() ) { 1055 error_log( 'Post Views Counter: measurement reset could not release its protected table fence.' ); 1056 return; 1057 } 1058 1059 if ( $visits !== null && $result !== 'entry_failed' && $result !== 'retirement_failed' ) { 1060 $promotion_raw = $result === 'completed' ? $completion['raw'] : $entry['raw']; 1061 1062 if ( ! is_string( $promotion_raw ) || ! $visits->promote_visit_reset_v0( $promotion_raw ) ) 1063 $result = 'promotion_failed'; 1064 } 1065 1066 if ( $result === 'completed' ) 1067 add_settings_error( 'reset_post_views', 'reset_post_views', __( 'All existing data deleted successfully.', 'post-views-counter' ), 'updated' ); 1068 elseif ( $result === 'entry_failed' ) 1069 add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Visits state could not be reset safely, so no data was deleted.', 'post-views-counter' ), 'error' ); 1070 else 1071 add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Error occurred. All existing data were not deleted.', 'post-views-counter' ), 'error' ); 990 1072 } 991 1073 -
post-views-counter/tags/1.8.0/includes/class-traffic-signals.php
r3514398 r3734102 10 10 */ 11 11 class Post_Views_Counter_Traffic_Signals { 12 13 /** 14 * Views floor on both sides of the comparison. 15 * 16 * @var int 17 */ 18 const MIN_VIEWS = 10; 19 20 /** 21 * The Views comparison fires above this change, in percent. 22 * 23 * @var int 24 */ 25 const VIEWS_CHANGE = 25; 26 27 /** 28 * The Entrances state fires at this change or more, in percent. 29 * 30 * @var int 31 */ 32 const ENTRANCES_CHANGE = 25; 33 34 /** 35 * Month comparisons read for this request, by period and post ID. 36 * 37 * @var array 38 */ 39 private static $primed = []; 12 40 13 41 /** … … 29 57 add_action( 'transition_post_status', [ $this, 'invalidate_signal_cache_on_status_change' ], 10, 3 ); 30 58 add_action( 'deleted_post', [ $this, 'invalidate_signal_cache' ], 10, 1 ); 59 add_filter( 'the_posts', [ $this, 'prime_list_signals' ], 10, 2 ); 31 60 } 32 61 … … 93 122 94 123 $signal_column = [ 95 'traffic_signal' => '<span class="pvc-signal-header" title="' . esc_attr__( 'Traffic Signals', 'post-views-counter' ) . '"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M14.828 14.828 21 21"/><path d="M21 16v5h-5"/><path d="m21 3-9 9-4-4-6 6"/><path d="M21 8V3h-5"/></svg><span class="screen-reader-text">' . esc_html__( 'Traffic Signals', 'post-views-counter' ) . '</span></span>'124 'traffic_signal' => '<span class="pvc-signal-header" data-pvc-tooltip="' . esc_attr__( 'Traffic Signals', 'post-views-counter' ) . '"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M14.828 14.828 21 21"/><path d="M21 16v5h-5"/><path d="m21 3-9 9-4-4-6 6"/><path d="M21 8V3h-5"/></svg><span class="screen-reader-text">' . esc_html__( 'Traffic Signals', 'post-views-counter' ) . '</span></span>' 96 125 ]; 97 126 … … 118 147 return; 119 148 } 149 150 // signals disabled after the column was registered: no read, no state 151 if ( ! $this->is_enabled() ) 152 return; 120 153 121 154 // check if user can see stats … … 134 167 ); 135 168 } else { 136 // anomaly detected - generic signal 169 // anomaly detected - generic signal; an Entrances state looks the same, Free never says which 137 170 printf( 138 171 '<span class="pvc-signal" role="tooltip" aria-label="%s" data-microtip-position="top" data-microtip-size="medium"><span class="pvc-insight pvc-insight-anomaly"></span></span>', … … 143 176 144 177 /** 178 * Read the signals of a posts list page with one query. 179 * 180 * Only rows whose signal is not cached are read; the result is kept for 181 * this request, never in the object cache. 182 * 183 * @param array $posts Posts returned by the main list query 184 * @param WP_Query $query Query object 185 * @return array Posts 186 */ 187 public function prime_list_signals( $posts, $query = null ) { 188 if ( ! is_admin() || empty( $posts ) || ! ( $query instanceof WP_Query ) || ! $query->is_main_query() || ! $this->is_enabled() ) 189 return $posts; 190 191 $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; 192 193 if ( ! $screen || $screen->base !== 'edit' || empty( $screen->post_type ) || $screen->post_type === 'attachment' ) 194 return $posts; 195 196 $pvc = Post_Views_Counter(); 197 198 if ( ! $pvc->options['display']['post_views_column'] || ! in_array( $screen->post_type, (array) $pvc->options['general']['post_types_count'], true ) ) 199 return $posts; 200 201 // the Views column is removed when stats are denied, and the signal column with it 202 if ( apply_filters( 'pvc_admin_display_post_views', true ) === false ) 203 return $posts; 204 205 $post_ids = []; 206 207 // read only the rows the cell may show 208 foreach ( $posts as $post ) { 209 if ( isset( $post->ID ) && apply_filters( 'pvc_admin_display_post_views', true, (int) $post->ID ) !== false ) 210 $post_ids[] = (int) $post->ID; 211 } 212 213 self::prime( $post_ids, $this->get_signal_now() ); 214 215 return $posts; 216 } 217 218 /** 219 * Read and keep the month comparisons of uncached rows for this request. 220 * 221 * @internal Called for a list page and by tests; not a public API. 222 * 223 * @param array $post_ids Post IDs 224 * @param DateTimeInterface $now Current time in the counting clock 225 * @return void 226 */ 227 public static function prime( $post_ids, $now ) { 228 $periods = self::get_signal_periods( $now ); 229 $misses = []; 230 231 foreach ( array_unique( array_filter( array_map( 'absint', (array) $post_ids ) ) ) as $post_id ) { 232 if ( wp_cache_get( 'pvc_signal_' . $post_id . '_' . $periods['period'], 'post_views_counter' ) === false ) 233 $misses[] = $post_id; 234 } 235 236 if ( empty( $misses ) ) 237 return; 238 239 $key = self::get_primed_key( $periods ); 240 241 foreach ( self::get_month_comparisons( $misses, $periods, $now ) as $post_id => $values ) { 242 self::$primed[$key][$post_id] = $values; 243 } 244 } 245 246 /** 247 * Forget the comparisons kept for this request. 248 * 249 * @internal For tests. 250 * 251 * @return void 252 */ 253 public static function reset_primed() { 254 self::$primed = []; 255 } 256 257 /** 145 258 * Detect traffic signal using simple Month-over-Month comparison. 146 259 * 147 * @param int $post_id Post ID 260 * @param int $post_id Post ID 261 * @param DateTimeInterface|null $now Current time in the counting clock 148 262 * @return array|null Signal data or null if no anomaly 149 263 */ 150 private function detect_signal( $post_id ) { 264 private function detect_signal( $post_id, $now = null ) { 265 $now = $now instanceof DateTimeInterface ? $now : $this->get_signal_now(); 266 $periods = self::get_signal_periods( $now ); 267 151 268 // check cache first 152 $cache_key = 'pvc_signal_' . $post_id ;269 $cache_key = 'pvc_signal_' . $post_id . '_' . $periods['period']; 153 270 $cache_group = 'post_views_counter'; 154 271 $cached = wp_cache_get( $cache_key, $cache_group ); 155 272 156 273 if ( $cached !== false ) { 274 // a cached Entrances state lasts only while both ranges stay derived 275 if ( is_array( $cached ) && ! empty( $cached['entrances'] ) && ! self::are_entrances_derived( $periods, $now ) ) { 276 wp_cache_delete( $cache_key, $cache_group ); 277 return null; 278 } 279 157 280 return $cached; 158 281 } 159 282 160 // get current month views 161 $current_date = new DateTime(); 162 $current_period = $current_date->format( 'Ym' ); 163 164 $current_total = (int) pvc_get_post_views( $post_id, $current_period ); 165 166 // minimum views threshold 167 if ( $current_total < 10 ) { 168 wp_cache_set( $cache_key, null, $cache_group, HOUR_IN_SECONDS ); 283 $values = self::get_month_comparison( $post_id, $periods, $now ); 284 285 // a failed read is silence, never cached 286 if ( $values === false ) { 169 287 return null; 170 288 } 171 289 172 // get previous month views (same number of days as current month-to-date) 173 $prev_date = clone $current_date; 174 $prev_date->modify( '-1 month' ); 175 $prev_year = $prev_date->format( 'Y' ); 176 $prev_month = $prev_date->format( 'm' ); 177 $prev_last_day = (int) $prev_date->format( 't' ); 178 $current_day = (int) $current_date->format( 'd' ); 179 // compare against the same number of days from last month (clamp to last day) 180 $end_day = min( $current_day, $prev_last_day ); 181 182 $prev_start = (int) ( $prev_year . $prev_month . '01' ); 183 $prev_end = (int) ( $prev_year . $prev_month . str_pad( (string) $end_day, 2, '0', STR_PAD_LEFT ) ); 184 185 $prev_total = (int) pvc_get_post_views( 186 $post_id, 187 '', 188 [ 189 'type' => 0, 190 'period_range' => [ $prev_start, $prev_end ] 191 ] 192 ); 193 194 // need both periods to compare 195 if ( $prev_total < 10 ) { 196 wp_cache_set( $cache_key, null, $cache_group, HOUR_IN_SECONDS ); 197 return null; 198 } 199 200 // calculate change percentage 201 $change_percent = ( ( $current_total - $prev_total ) / $prev_total ) * 100; 202 203 // threshold: 25% change (up or down) 204 if ( abs( $change_percent ) > 25 ) { 290 // current month views: month to date, or its first days on the 29th-31st; null when unproven 291 $current_total = $values['current']; 292 293 // previous month views (same number of days as current month-to-date), null when pruned 294 $prev_total = $values['previous']; 295 296 if ( self::is_views_anomaly( $current_total, $prev_total ) ) { 205 297 $result = [ 206 298 'anomaly' => true, 207 'change_percent' => round( $change_percent)299 'change_percent' => round( ( ( $current_total - $prev_total ) / $prev_total ) * 100 ) 208 300 ]; 301 } elseif ( self::evaluate_entrances_state( self::get_entrances_evidence( $values ) ) !== null ) { 302 // the state carries no number and no direction 303 $result = [ 'entrances' => true ]; 209 304 } else { 210 305 $result = null; 211 306 } 212 307 213 // cache for 1 hour 214 wp_cache_set( $cache_key, $result, $cache_group, HOUR_IN_SECONDS ); 308 // cache for 1 hour, unless the Entrances read failed 309 if ( ! isset( $values['cacheable'] ) || $values['cacheable'] ) { 310 wp_cache_set( $cache_key, $result, $cache_group, HOUR_IN_SECONDS ); 311 } 215 312 216 313 return $result; 314 } 315 316 /** 317 * Whether the Views comparison fires. 318 * 319 * @param int|null $current Current month Views on the compared days, null when unknown 320 * @param int|null $previous Views on the same days of the previous month, null when unknown 321 * @return bool 322 */ 323 private static function is_views_anomaly( $current, $previous ) { 324 // minimum views threshold on both sides 325 if ( ! is_int( $current ) || ! is_int( $previous ) || $current < self::MIN_VIEWS || $previous < self::MIN_VIEWS ) 326 return false; 327 328 // threshold: more than 25% change (up or down) 329 return abs( ( ( $current - $previous ) / $previous ) * 100 ) > self::VIEWS_CHANGE; 330 } 331 332 /** 333 * Decide the Entrances state. 334 * 335 * Shown only while the Views comparison is silent: month-to-date Entrances 336 * against the same days of the previous month, on eligible data. A 337 * previous value of 0 is a measured zero (the range is derived) and 338 * triggers a rise without a percentage. 339 * 340 * @internal Shared by Traffic Signals and extension insights; not a public API. 341 * 342 * @param array $evidence { 343 * @type int|null $views_current Month-to-date Views 344 * @type int|null $views_previous Views of the previous range; null unless its month is complete 345 * @type int|null $entrances_current Month-to-date Entrances 346 * @type int|null $entrances_previous Entrances of the previous range; null unless complete and at parity 347 * @type bool $derived_current Visits derived for the current range 348 * @type bool $derived_previous Visits derived for the previous range 349 * } 350 * @return array|null [ 'direction' => up|down ], or null 351 */ 352 public static function evaluate_entrances_state( $evidence ) { 353 $evidence = is_array( $evidence ) ? $evidence : []; 354 $value = static function( $key ) use ( $evidence ) { 355 return isset( $evidence[$key] ) && is_int( $evidence[$key] ) ? $evidence[$key] : null; 356 }; 357 $views_current = $value( 'views_current' ); 358 $views_previous = $value( 'views_previous' ); 359 $current = $value( 'entrances_current' ); 360 $previous = $value( 'entrances_previous' ); 361 362 // the Views state wins 363 if ( $views_current === null || $views_previous === null || self::is_views_anomaly( $views_current, $views_previous ) ) 364 return null; 365 366 $check = Post_Views_Counter_Entrances_Eligibility::check( 367 [ 368 [ 'views' => $views_current, 'entrances' => $current, 'derived_available' => ! empty( $evidence['derived_current'] ) ], 369 [ 'views' => $views_previous, 'entrances' => $previous, 'derived_available' => ! empty( $evidence['derived_previous'] ) ] 370 ], 371 self::MIN_VIEWS 372 ); 373 374 if ( ! $check['eligible'] || $current === $previous ) 375 return null; 376 377 // measured-zero trigger: from 0 any rise to the floor is unusual 378 if ( $previous > 0 && abs( $current - $previous ) * 100 < self::ENTRANCES_CHANGE * $previous ) 379 return null; 380 381 return [ 'direction' => $current > $previous ? 'up' : 'down' ]; 382 } 383 384 /** 385 * Build the Entrances evidence of a month comparison. 386 * 387 * @param array $values Result of get_month_comparison() 388 * @return array 389 */ 390 private static function get_entrances_evidence( $values ) { 391 $entrances = isset( $values['entrances'] ) && is_array( $values['entrances'] ) ? $values['entrances'] : []; 392 393 return [ 394 'views_current' => $values['current'], 395 'views_previous' => $values['previous'], 396 'entrances_current' => isset( $entrances['current'] ) ? $entrances['current'] : null, 397 'entrances_previous' => isset( $entrances['previous'] ) ? $entrances['previous'] : null, 398 'derived_current' => ! empty( $entrances['derived_current'] ), 399 'derived_previous' => ! empty( $entrances['derived_previous'] ) 400 ]; 401 } 402 403 /** 404 * Read a post's month-to-date Views and its equal-day comparison. 405 * 406 * A primed list page answers from memory; otherwise the post is read on its 407 * own with the list statement. 408 * 409 * @internal Shared with the Entrances state; not a public API. 410 * 411 * @param int $post_id Post ID 412 * @param array $periods Result of get_signal_periods() 413 * @param DateTimeInterface|null $now Current time in the counting clock 414 * @return array|false See get_month_comparisons(); false when the read failed 415 */ 416 public static function get_month_comparison( $post_id, $periods, $now = null ) { 417 $post_id = (int) $post_id; 418 $key = self::get_primed_key( $periods ); 419 420 if ( isset( self::$primed[$key] ) && array_key_exists( $post_id, self::$primed[$key] ) ) 421 return self::$primed[$key][$post_id]; 422 423 $now = $now instanceof DateTimeInterface ? $now : new DateTimeImmutable( 'now', Post_Views_Counter_Visits_Query::get_timezone() ); 424 $values = self::get_month_comparisons( [ $post_id ], $periods, $now ); 425 426 return isset( $values[$post_id] ) ? $values[$post_id] : false; 427 } 428 429 /** 430 * Read month-to-date Views and their equal-day comparison for posts, in one query. 431 * 432 * The previous range counts only when the previous month's daily rows are 433 * complete: their sum equals its monthly row. The daily cleanup deletes only 434 * daily rows, so a pruned day with Views leaves the two unequal. Entrances 435 * (the `visits` column) are read in the same statement only while both 436 * ranges are derived; the previous range's Entrances also need parity: 437 * the month's daily `visits` sum equals its monthly row's. A failed read 438 * with Entrances falls back to one Views-only read, and nothing from it is 439 * cached. 440 * 441 * When the previous range is shorter than month to date (the 29th-31st after a shorter month), the current side is the same number of first 442 * days of the current month, under the same rule: its daily rows must add 443 * up to its monthly row, and for Entrances their `visits` too. Otherwise 444 * the current value is null and the signal is silent. 445 * 446 * @param array $post_ids Post IDs 447 * @param array $periods Result of get_signal_periods() 448 * @param DateTimeInterface $now Current time in the counting clock 449 * @return array Values by post ID: [ 'current' => int|null, 'previous' => int|null, 450 * 'entrances' => [ 'current' => int|null, 'previous' => int|null, 451 * 'derived_current' => bool, 'derived_previous' => bool ], 452 * 'cacheable' => bool ], or false per post when the read failed 453 */ 454 private static function get_month_comparisons( $post_ids, $periods, $now ) { 455 $post_ids = array_values( array_unique( array_filter( array_map( 'absint', (array) $post_ids ) ) ) ); 456 $result = []; 457 458 if ( empty( $post_ids ) ) 459 return $result; 460 461 $pvc = Post_Views_Counter(); 462 $no_entrances = [ 'current' => null, 'previous' => null, 'derived_current' => false, 'derived_previous' => false ]; 463 464 // no site data yet: nothing to compare 465 if ( isset( $pvc->visits ) && method_exists( $pvc->visits, 'is_site_data_accessible' ) && ! $pvc->visits->is_site_data_accessible() ) { 466 foreach ( $post_ids as $post_id ) { 467 $result[$post_id] = [ 'current' => 0, 'previous' => null, 'entrances' => $no_entrances, 'cacheable' => true ]; 468 } 469 470 return $result; 471 } 472 473 $derived = self::get_entrances_availability( $periods, $now ); 474 $with_entrances = $derived['current'] && $derived['previous']; 475 $rows = self::query_month_comparisons( $post_ids, $periods, $with_entrances ); 476 $cacheable = true; 477 478 // Entrances must never cost the Views: one Views-only read, nothing cached 479 if ( $rows === false && $with_entrances ) { 480 $with_entrances = false; 481 $cacheable = false; 482 $rows = self::query_month_comparisons( $post_ids, $periods, false ); 483 } 484 485 if ( $rows === false ) { 486 foreach ( $post_ids as $post_id ) { 487 $result[$post_id] = false; 488 } 489 490 return $result; 491 } 492 493 foreach ( $post_ids as $post_id ) { 494 $row = isset( $rows[$post_id] ) ? $rows[$post_id] : []; 495 $sum = static function( $column ) use ( $row ) { 496 return (int) ( isset( $row[$column] ) ? $row[$column] : 0 ); 497 }; 498 $complete = $sum( 'previous_daily_views' ) === $sum( 'previous_month_views' ); 499 $current = $sum( 'current_views' ); 500 $current_entrances = $with_entrances ? $sum( 'current_entrances' ) : null; 501 502 // the current month's first days count only when its daily rows add up to its monthly row 503 if ( ! empty( $periods['current'] ) ) { 504 $current = $sum( 'current_daily_views' ) === $sum( 'current_views' ) ? $sum( 'current_range_views' ) : null; 505 $current_entrances = $current !== null && $with_entrances && $sum( 'current_daily_entrances' ) === $sum( 'current_entrances' ) ? $sum( 'current_range_entrances' ) : null; 506 } 507 508 $entrances = $no_entrances; 509 510 if ( $with_entrances ) { 511 $entrances = [ 512 'current' => $current_entrances, 513 'previous' => $complete && $sum( 'previous_daily_entrances' ) === $sum( 'previous_month_entrances' ) ? $sum( 'previous_entrances' ) : null, 514 'derived_current' => true, 515 'derived_previous' => true 516 ]; 517 } 518 519 $result[$post_id] = [ 520 'current' => $current, 521 'previous' => $complete ? $sum( 'previous_views' ) : null, 522 'entrances' => $entrances, 523 'cacheable' => $cacheable 524 ]; 525 } 526 527 return $result; 528 } 529 530 /** 531 * Run the month comparison statement for posts. 532 * 533 * @param array $post_ids Post IDs 534 * @param array $periods Result of get_signal_periods() 535 * @param bool $with_entrances Whether to sum `visits` too 536 * @return array|false Rows by post ID, or false when the read failed 537 */ 538 private static function query_month_comparisons( $post_ids, $periods, $with_entrances ) { 539 global $wpdb; 540 541 $from = (string) $periods['comparison'][0]; 542 $to = (string) $periods['comparison'][1]; 543 $previous_month = substr( $from, 0, 6 ); 544 $month_start = DateTimeImmutable::createFromFormat( '!Ymd', $previous_month . '01', new DateTimeZone( 'UTC' ) ); 545 $month_end = $previous_month . $month_start->format( 't' ); 546 $content_sql = pvc_post_views_has_content_column() ? ' AND `content` = 0' : ''; 547 $columns = [ 'count' => 'views' ]; 548 549 // `visits` is in no index; keep the per-post index instead of the (type, period) primary key 550 if ( $with_entrances ) 551 $columns['visits'] = 'entrances'; 552 553 // on the 29th-31st after a shorter month: the current month's first days and its daily sum 554 $current = empty( $periods['current'] ) ? null : [ (string) $periods['current'][0], (string) $periods['current'][1] ]; 555 $current_end = $current === null ? '' : $periods['period'] . DateTimeImmutable::createFromFormat( '!Ymd', $periods['period'] . '01', new DateTimeZone( 'UTC' ) )->format( 't' ); 556 $select = []; 557 $params = []; 558 559 foreach ( $columns as $column => $name ) { 560 $select[] = 'COALESCE( SUM( CASE WHEN `type` = 2 AND `period` = %s THEN `' . $column . '` ELSE 0 END ), 0 ) AS current_' . $name; 561 $select[] = 'COALESCE( SUM( CASE WHEN `type` = 0 AND `period` >= %s AND `period` <= %s THEN `' . $column . '` ELSE 0 END ), 0 ) AS previous_' . $name; 562 $params = array_merge( $params, [ (string) $periods['period'], $from, $to ] ); 563 564 // the daily rows read are the previous month's only, unless the current month's are read too 565 if ( $current === null ) 566 $select[] = 'COALESCE( SUM( CASE WHEN `type` = 0 THEN `' . $column . '` ELSE 0 END ), 0 ) AS previous_daily_' . $name; 567 else { 568 $select[] = 'COALESCE( SUM( CASE WHEN `type` = 0 AND `period` >= %s AND `period` <= %s THEN `' . $column . '` ELSE 0 END ), 0 ) AS previous_daily_' . $name; 569 $params = array_merge( $params, [ $previous_month . '01', $month_end ] ); 570 } 571 572 $select[] = 'COALESCE( SUM( CASE WHEN `type` = 2 AND `period` = %s THEN `' . $column . '` ELSE 0 END ), 0 ) AS previous_month_' . $name; 573 $params[] = $previous_month; 574 575 if ( $current !== null ) { 576 $select[] = 'COALESCE( SUM( CASE WHEN `type` = 0 AND `period` >= %s AND `period` <= %s THEN `' . $column . '` ELSE 0 END ), 0 ) AS current_range_' . $name; 577 $select[] = 'COALESCE( SUM( CASE WHEN `type` = 0 AND `period` >= %s AND `period` <= %s THEN `' . $column . '` ELSE 0 END ), 0 ) AS current_daily_' . $name; 578 $params = array_merge( $params, [ $current[0], $current[1], $periods['period'] . '01', $current_end ] ); 579 } 580 } 581 582 $sql = $wpdb->prepare( 583 'SELECT `id`, 584 ' . implode( ",\n\t\t\t\t", $select ) . ' 585 FROM `' . $wpdb->prefix . 'post_views`' . ( $with_entrances ? ' FORCE INDEX (`id_type_period_count`)' : '' ) . ' 586 WHERE `id` IN (' . implode( ', ', array_fill( 0, count( $post_ids ), '%d' ) ) . ')' . $content_sql . ' 587 AND ( ( `type` = 2 AND `period` IN ( %s, %s ) ) OR ( `type` = 0 AND `period` >= %s AND `period` <= %s )' . ( $current === null ? '' : ' OR ( `type` = 0 AND `period` >= %s AND `period` <= %s )' ) . ' ) 588 GROUP BY `id`', 589 array_merge( $params, $post_ids, [ (string) $periods['period'], $previous_month, $previous_month . '01', $month_end ], $current === null ? [] : [ $periods['period'] . '01', $current_end ] ) 590 ); 591 592 // a table without the index fails here and takes the Views-only fallback 593 $suppress = $with_entrances ? $wpdb->suppress_errors( true ) : null; 594 $wpdb->last_error = ''; 595 $rows = $wpdb->get_results( $sql, ARRAY_A ); 596 $failed = $wpdb->last_error !== '' || ! is_array( $rows ); 597 598 if ( $with_entrances ) 599 $wpdb->suppress_errors( $suppress ); 600 601 if ( $failed ) 602 return false; 603 604 $by_id = []; 605 606 foreach ( $rows as $row ) { 607 if ( isset( $row['id'] ) ) 608 $by_id[(int) $row['id']] = $row; 609 } 610 611 return $by_id; 612 } 613 614 /** 615 * Whether Visits are derived for both compared ranges. 616 * 617 * @param array $periods Result of get_signal_periods() 618 * @param DateTimeInterface $now Current time in the counting clock 619 * @return array [ 'current' => bool, 'previous' => bool ] 620 */ 621 private static function get_entrances_availability( $periods, $now ) { 622 $current = Post_Views_Counter_Entrances_Eligibility::get_day_range_availability( $periods['period'] . '01', empty( $periods['current'] ) ? $now->format( 'Ymd' ) : (string) $periods['current'][1], $now ); 623 $previous = Post_Views_Counter_Entrances_Eligibility::get_day_range_availability( $periods['comparison'][0], $periods['comparison'][1], $now ); 624 625 return [ 'current' => $current['derived_available'], 'previous' => $previous['derived_available'] ]; 626 } 627 628 /** 629 * Whether a cached Entrances state still stands on derived ranges. 630 * 631 * @param array $periods Result of get_signal_periods() 632 * @param DateTimeInterface $now Current time in the counting clock 633 * @return bool 634 */ 635 private static function are_entrances_derived( $periods, $now ) { 636 $derived = self::get_entrances_availability( $periods, $now ); 637 638 return $derived['current'] && $derived['previous']; 639 } 640 641 /** 642 * Key of the comparisons kept for this request. 643 * 644 * @param array $periods Result of get_signal_periods() 645 * @return string 646 */ 647 private static function get_primed_key( $periods ) { 648 return get_current_blog_id() . ':' . $periods['period'] . ':' . implode( '-', $periods['comparison'] ) . ( empty( $periods['current'] ) ? '' : ':' . implode( '-', $periods['current'] ) ); 649 } 650 651 /** 652 * Get the current time in the clock that buckets the stored periods. 653 * 654 * @return DateTimeImmutable 655 */ 656 private function get_signal_now() { 657 return new DateTimeImmutable( 'now', Post_Views_Counter_Visits_Query::get_timezone() ); 658 } 659 660 /** 661 * Get the current month and its equal-day comparison range. 662 * 663 * The previous month is stepped back from the first day of the current 664 * month, so the 29th-31st cannot roll over into the current month. Both 665 * sides hold the same days: on the 29th-31st after a shorter 666 * month the current side stops where the previous month does. 667 * 668 * @param DateTimeInterface $now Current time in the counting clock 669 * @return array Current period (Ym), comparison day range [Ymd, Ymd], and 670 * the current day range [Ymd, Ymd] when it is shorter than 671 * month to date, else null (the monthly row) 672 */ 673 private static function get_signal_periods( $now ) { 674 $month_start = DateTimeImmutable::createFromFormat( '!Y-m-d', $now->format( 'Y-m-01' ), $now->getTimezone() ); 675 $prev_month = $month_start->modify( '-1 month' ); 676 $day = (int) $now->format( 'j' ); 677 678 // compare against the same number of days from last month (clamp to last day) 679 $end_day = min( $day, (int) $prev_month->format( 't' ) ); 680 $end = str_pad( (string) $end_day, 2, '0', STR_PAD_LEFT ); 681 682 return [ 683 'period' => $now->format( 'Ym' ), 684 'comparison' => [ 685 (int) ( $prev_month->format( 'Ym' ) . '01' ), 686 (int) ( $prev_month->format( 'Ym' ) . $end ) 687 ], 688 'current' => $end_day < $day ? [ (int) ( $now->format( 'Ym' ) . '01' ), (int) ( $now->format( 'Ym' ) . $end ) ] : null 689 ]; 217 690 } 218 691 … … 260 733 */ 261 734 public function invalidate_signal_cache( $post_id ) { 262 $cache_key = 'pvc_signal_' . $post_id; 735 // older periods' entries expire within their one-hour lifetime 736 $periods = self::get_signal_periods( $this->get_signal_now() ); 737 $cache_key = 'pvc_signal_' . $post_id . '_' . $periods['period']; 263 738 $cache_group = 'post_views_counter'; 264 739 wp_cache_delete( $cache_key, $cache_group ); 740 unset( self::$primed[self::get_primed_key( $periods )][(int) $post_id] ); 265 741 } 266 742 … … 271 747 */ 272 748 public function flush_all_signals_cache() { 749 // comparisons read earlier in this request predate the flush or reset 750 self::$primed = []; 751 273 752 // WordPress doesn't support wildcard cache deletion 274 753 // We rely on natural cache expiration (1 hour) for bulk invalidation -
post-views-counter/tags/1.8.0/includes/class-update.php
r3537950 r3734102 99 99 if ( $pvc->counter->using_object_cache( true ) ) { 100 100 // flush data from cache 101 $pvc->counter->flush_cache_to_db(); 101 if ( ! $pvc->counter->flush_cache_to_db() ) 102 return; 102 103 } 103 104 … … 184 185 185 186 $pvc->options['general']['time_between_counts'] = $normalized_time_between_counts; 187 } 188 189 // update 1.7.16+ - unify frontend counter labels 190 if ( version_compare( $current_db_version, '1.7.16', '<' ) ) { 191 $display = get_option( 'post_views_counter_settings_display', [] ); 192 193 if ( ! is_array( $display ) ) 194 $display = []; 195 196 // rewrite ONLY the exact legacy defaults; every customised value is preserved 197 $legacy_labels = [ 198 'label' => [ 'Post Views:', 'Views:' ] 199 ]; 200 $labels_changed = false; 201 202 foreach ( $legacy_labels as $key => $pair ) { 203 list( $legacy, $unified ) = $pair; 204 205 if ( ! isset( $display[$key] ) || ! is_string( $display[$key] ) || $display[$key] !== $legacy ) 206 continue; 207 208 $display[$key] = $unified; 209 $pvc->options['display'][$key] = $unified; 210 $labels_changed = true; 211 } 212 213 if ( $labels_changed ) 214 update_option( 'post_views_counter_settings_display', $display ); 186 215 } 187 216 -
post-views-counter/tags/1.8.0/includes/functions.php
r3640258 r3734102 49 49 } 50 50 51 if ( isset( Post_Views_Counter()->visits ) && method_exists( Post_Views_Counter()->visits, 'is_site_data_accessible' ) && ! Post_Views_Counter()->visits->is_site_data_accessible() ) 52 return (int) apply_filters( 'pvc_get_post_views', 0, $post_id, $period, $args ); 53 54 // Resolve Core-supported named and storage periods before the compatibility 55 // filter runs. Unknown helper periods still receive one filter opportunity. 56 $has_explicit_range = isset( $args['period_range'] ) || isset( $args['period_from'], $args['period_to'] ); 57 $normalized_period = $has_explicit_range ? null : pvc_normalize_views_period( $period, $args ); 58 51 59 // set where clause 52 60 $where = [ 'type' => 'type = 4' ]; 53 61 54 // override type if explicitly provided in args 62 if ( $normalized_period !== null ) { 63 $where['type'] = 'type = ' . (int) $normalized_period['type']; 64 65 if ( (int) $normalized_period['type'] === 4 ) 66 $where['period'] = "period = 'total'"; 67 elseif ( $normalized_period['period_from'] === $normalized_period['period_to'] ) 68 $where['period'] = 'CAST( period AS SIGNED ) = ' . (int) $normalized_period['period_from']; 69 else 70 $where['period'] = 'CAST( period AS SIGNED ) <= ' . (int) $normalized_period['period_to'] . ' AND CAST( period AS SIGNED ) >= ' . (int) $normalized_period['period_from']; 71 } 72 73 $has_explicit_type = false; 74 75 // Override type if explicitly provided in args. Historically an explicit 76 // type without a range selected every row of that storage type, so it must 77 // not retain a canonical period predicate from the named period argument. 55 78 if ( isset( $args['type'] ) ) { 56 79 $where['type'] = 'type = ' . (int) $args['type']; 80 $has_explicit_type = true; 57 81 } elseif ( isset( $args['period_type'] ) ) { 58 82 $period_type = sanitize_key( $args['period_type'] ); … … 66 90 if ( isset( $type_map[ $period_type ] ) ) { 67 91 $where['type'] = 'type = ' . $type_map[ $period_type ]; 92 $has_explicit_type = true; 68 93 } 69 94 } 95 96 if ( $has_explicit_type && ! $has_explicit_range ) 97 unset( $where['period'] ); 70 98 71 99 // optional period range (e.g., for day-based ranges within a month) … … 91 119 92 120 // default to day type when using explicit ranges and no type set 93 if ( ! isset( $ where['type'] ) ) {121 if ( ! isset( $args['type'] ) && ! isset( $args['period_type'] ) ) { 94 122 $where['type'] = 'type = 0'; 95 123 } … … 130 158 131 159 // update where clause 132 $where = apply_filters( 'pvc_get_post_views_period_where', $where, $period, $post_id, $args ); 160 $filter_args = $args; 161 162 if ( $normalized_period !== null ) 163 $filter_args['_pvc_core_period_resolved'] = $normalized_period; 164 165 $where = apply_filters( 'pvc_get_post_views_period_where', $where, $period, $post_id, $filter_args ); 166 167 if ( ! is_array( $where ) ) 168 return 0; 169 170 // Explicit content is authoritative across Core and extension callbacks. 171 if ( isset( $args['content'] ) ) 172 $where['content'] = 'content = ' . (int) $args['content']; 133 173 134 174 // updated where clause 135 175 $_where = []; 176 $strict_period_selector = false; 136 177 137 178 // sanitize where clause 138 179 foreach ( $where as $index => $value ) { 139 if ( $index === 'type' || $index === 'content' ) 140 $_where[$index] = preg_replace( '/[^0-9]/', '', $value ); 180 if ( $index === 'type' || $index === 'content' ) { 181 if ( ! is_scalar( $value ) ) 182 continue; 183 184 $selector = preg_replace( '/[^0-9]/', '', (string) $value ); 185 186 if ( $selector !== '' ) 187 $_where[$index] = $selector; 188 } 141 189 elseif ( $index === 'period' ) { 142 if ( is_string( $value ) && preg_match( "/period\s*=\s*'?total'?/i", $value ) ) { 190 if ( ! is_string( $value ) ) 191 continue; 192 193 $period_operand = '(?:CAST\s*\(\s*period\s+AS\s+(?:SIGNED|UNSIGNED)\s*\)|period)'; 194 195 if ( preg_match( "/^\s*period\s*=\s*'?total'?\s*$/i", $value ) ) { 143 196 $_where['period'] = [ 'total' ]; 197 $strict_period_selector = true; 144 198 continue; 145 199 } … … 148 202 149 203 // any values? 150 if ( $values !== false && $values > 0 )204 if ( $values !== false && $values > 0 && $values <= 2 ) 151 205 $_where['period'] = $matches[0]; 206 207 if ( preg_match( '/^\s*' . $period_operand . "\s*=\s*'?\d+'?\s*$/i", $value ) ) 208 $strict_period_selector = true; 209 elseif ( preg_match( '/^\s*' . $period_operand . "\s*<=\s*'?\d+'?\s+AND\s+" . $period_operand . "\s*>=\s*'?\d+'?\s*$/i", $value ) ) 210 $strict_period_selector = true; 211 elseif ( preg_match( '/^\s*' . $period_operand . "\s*>=\s*'?\d+'?\s+AND\s+" . $period_operand . "\s*<=\s*'?\d+'?\s*$/i", $value ) ) 212 $strict_period_selector = true; 213 elseif ( preg_match( '/^\s*' . $period_operand . "\s+BETWEEN\s+'?\d+'?\s+AND\s+'?\d+'?\s*$/i", $value ) ) 214 $strict_period_selector = true; 152 215 } 153 216 } 217 218 // A raw SQL-fragment filter remains a helper-only compatibility mechanism. 219 // Unknown periods fail closed unless it supplied a complete, strictly 220 // recognized storage selector. REST never consults this hook. 221 if ( $normalized_period === null && ! $range_from && ! $range_to && ( ! isset( $_where['type'], $_where['period'] ) || ! $strict_period_selector ) ) 222 return 0; 154 223 155 224 // get current number of ids 156 225 $ids_count = count( $numbers ); 157 226 158 $where_ clause = '';159 227 $where_parts = []; 228 160 229 // add post ids if needed 161 if ( $ids_count ) { 162 $where_clause .= " WHERE id IN (" . implode( ',', array_fill( 0, $ids_count, '%d' ) ) . ") AND"; 163 } else { 164 $where_clause .= " WHERE"; 165 } 230 if ( $ids_count ) 231 $where_parts[] = "id IN (" . implode( ',', array_fill( 0, $ids_count, '%d' ) ) . ")"; 166 232 167 233 // validate where clause 168 234 foreach( $_where as $index => $value ) { 169 235 if ( $index === 'type' ) { 170 $where_ clause .= 'type = %d';236 $where_parts[] = 'type = %d'; 171 237 $numbers[] = (int) $value; 172 238 } elseif ( $index === 'content' && pvc_post_views_has_content_column() ) { 173 $where_ clause .= ' ANDcontent = %d';239 $where_parts[] = 'content = %d'; 174 240 $numbers[] = (int) $value; 175 241 } elseif ( $index === 'period' ) { … … 178 244 if ( $nop === 1 ) { 179 245 if ( $_where['period'][0] === 'total' ) { 180 $where_ clause .= ' ANDperiod = %s';246 $where_parts[] = 'period = %s'; 181 247 $numbers[] = 'total'; 182 248 } else { 183 $where_ clause .= ' ANDCAST( period AS SIGNED ) = %d';249 $where_parts[] = 'CAST( period AS SIGNED ) = %d'; 184 250 $numbers[] = (int) $_where['period'][0]; 185 251 } 186 252 } elseif ( $nop === 2 ) { 187 $where_clause .= ' AND CAST( period AS SIGNED ) <= %d AND CAST( period AS SIGNED ) >= %d'; 188 $numbers[] = (int) $_where['period'][0]; 189 $numbers[] = (int) $_where['period'][1]; 253 // Recognized selectors may list bounds in either order, so normalize 254 // them instead of trusting the extracted positional order. 255 $bounds = [ 256 (int) $_where['period'][0], 257 (int) $_where['period'][1] 258 ]; 259 260 $where_parts[] = 'CAST( period AS SIGNED ) <= %d AND CAST( period AS SIGNED ) >= %d'; 261 $numbers[] = max( $bounds ); 262 $numbers[] = min( $bounds ); 190 263 } 191 264 } 192 265 } 266 267 if ( empty( $where_parts ) ) 268 return 0; 269 270 $where_clause = ' WHERE ' . implode( ' AND ', $where_parts ); 193 271 194 272 // prepare query … … 225 303 */ 226 304 function pvc_post_views_has_content_column() { 227 global $wpdb; 228 229 static $has_content_column = null; 230 231 // check column existence only once 232 if ( $has_content_column === null ) { 233 // check content column using SHOW COLUMNS (more robust than information_schema) 234 $columns = $wpdb->get_col( "SHOW COLUMNS FROM " . $wpdb->prefix . "post_views LIKE 'content'" ); 235 236 // cache result 237 $has_content_column = ! empty( $columns ); 238 } 305 $status = isset( Post_Views_Counter()->visits ) ? Post_Views_Counter()->visits->get_shared_content_column_status() : false; 306 307 // On an ambiguous probe, requiring the discriminator fails closed on a legacy 308 // schema instead of silently mixing extended content rows that share an ID. 309 $has_content_column = $status === null ? true : $status; 239 310 240 311 // always allow override via filter (applied on every call) … … 322 393 $query_data = array_merge( $query_data, array_values( $args['post_id'] ), array_values( $args['post_type'] ) ); 323 394 324 // set where clause 325 $where = apply_filters( 'pvc_get_views_period_where', [], $args ); 395 // set where clause, post rows only when the table stores other content 396 $where = []; 397 398 if ( pvc_post_views_has_content_column() ) 399 $where['content'] = 'pvc.content = 0'; 400 401 $where = apply_filters( 'pvc_get_views_period_where', $where, $args ); 402 403 // every period of one type has one length of digits (Ymd, oW, Ym, Y), so 404 // a same-length string bound selects the rows a numeric one would and 405 // keeps the (type, period) keys usable, which CAST( period ) defeats 406 $period_sql = static function( $period ) { 407 return "'" . preg_replace( '/[^0-9]/', '', (string) $period ) . "'"; 408 }; 326 409 327 410 // check fields … … 409 492 if ( isset( $chunk['week'] ) ) { 410 493 $where['type'] = 'pvc.type = 1'; 411 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int)( $chunk['year'] . $chunk['week'] );494 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period " . $chunk['type'] . " " . $period_sql( $chunk['year'] . $chunk['week'] ); 412 495 } 413 496 // year, month … … 416 499 if ( isset( $chunk['day'] ) ) { 417 500 $where['type'] = 'pvc.type = 0'; 418 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int)( $chunk['year'] . $chunk['month'] . $chunk['day'] );501 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period " . $chunk['type'] . " " . $period_sql( $chunk['year'] . $chunk['month'] . $chunk['day'] ); 419 502 } 420 503 // year, month 421 504 else { 422 505 $where['type'] = 'pvc.type = 2'; 423 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int)( $chunk['year'] . $chunk['month'] );506 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period " . $chunk['type'] . " " . $period_sql( $chunk['year'] . $chunk['month'] ); 424 507 } 425 508 // year 426 509 } else { 427 510 $where['type'] = 'pvc.type = 3'; 428 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int)( $chunk['year'] );511 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period " . $chunk['type'] . " " . $period_sql( $chunk['year'] ); 429 512 } 430 513 // month … … 487 570 $monday_month = $date->format( 'm' ); 488 571 572 // and its calendar year: week 1 may start in the previous one 573 $monday_year = $date->format( 'Y' ); 574 489 575 // prepare range 490 576 for( $i = 1; $i <= 6; $i++ ) { … … 500 586 501 587 $where['type'] = 'pvc.type = 0'; 502 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) >= " . (int) ( $year . $monday_month . $monday ) . " AND CAST( pvc.period AS SIGNED ) <= " . (int)( $date->format( 'Y' ) . $sunday_month . $date->format( 'd' ) );588 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period >= " . $period_sql( $monday_year . $monday_month . $monday ) . " AND pvc.period <= " . $period_sql( $date->format( 'Y' ) . $sunday_month . $date->format( 'd' ) ); 503 589 } else { 504 590 $where['type'] = 'pvc.type = 1'; 505 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int)( $year . $week );591 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period = " . $period_sql( $year . $week ); 506 592 } 507 593 // year, month … … 514 600 515 601 $where['type'] = 'pvc.type = 0'; 516 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int)( $year . $month . $day );602 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period = " . $period_sql( $year . $month . $day ); 517 603 // year, month 518 604 } else { … … 530 616 531 617 $where['type'] = 'pvc.type = 0'; 532 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) >= " . (int) ( $year . $month ) . "01 AND CAST( pvc.period AS SIGNED ) <= " . (int)( $year . $month . $last );618 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period >= " . $period_sql( $year . $month . '01' ) . " AND pvc.period <= " . $period_sql( $year . $month . $last ); 533 619 } else { 534 620 $where['type'] = 'pvc.type = 2'; 535 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int)( $year . $month );621 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period = " . $period_sql( $year . $month ); 536 622 } 537 623 } … … 548 634 549 635 $where['type'] = 'pvc.type = 2'; 550 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) >= " . (int) ( $year ) . "01 AND CAST( pvc.period AS SIGNED ) <= " . (int) ( $year ) . "12";636 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period >= " . $period_sql( $year . '01' ) . " AND pvc.period <= " . $period_sql( $year . '12' ); 551 637 } else { 552 638 $where['type'] = 'pvc.type = 3'; 553 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int)( $year );639 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND pvc.period = " . $period_sql( $year ); 554 640 } 555 641 } … … 577 663 578 664 // update where clause 579 $where['type'] = [ 'pvc.type = 4' ];665 $where['type'] = 'pvc.type = 4'; 580 666 581 667 $query = $wpdb->prepare( … … 619 705 620 706 /** 707 * Normalize a Views period to the canonical shared-table selector. 708 * 709 * Pluggable: a theme or plugin may define this before the plugin loads. 710 * 711 * @since 1.7.16 712 * 713 * @param mixed $period Requested period. 714 * @param array $args Optional explicit period arguments. 715 * 716 * @return array|null Normalized period, or null when the request is invalid. 717 */ 718 if ( ! function_exists( 'pvc_normalize_views_period' ) ) { 719 function pvc_normalize_views_period( $period = 'total', $args = [] ) { 720 return Post_Views_Counter_Visits_Query::normalize_views_period( $period, $args ); 721 } 722 } 723 724 /** 725 * Normalize one Visit period into storage and derived-range semantics. 726 * 727 * Availability ranges are half-open. Storage day ranges remain inclusive because 728 * the table stores one YYYYMMDD key per calendar day. 729 * 730 * Pluggable: a theme or plugin may define this before the plugin loads. 731 * 732 * @since 1.7.16 733 * 734 * @param string|array $period Named or explicit storage period. 735 * @param array $args Optional explicit range/type arguments. 736 * 737 * @return array|null Normalized period, or null when the request is invalid. 738 */ 739 if ( ! function_exists( 'pvc_normalize_visits_period' ) ) { 740 function pvc_normalize_visits_period( $period = 'total', $args = [] ) { 741 return Post_Views_Counter_Visits_Query::normalize_period( $period, $args ); 742 } 743 } 744 745 /** 746 * Get aggregate post Visits for an explicit range. 747 * 748 * @since 1.7.16 749 * 750 * @param array $args Query arguments. 751 * 752 * @return int|array|null Scalar or availability-bearing date result. Integer 753 * zero is a stored zero; null means Visits are 754 * unavailable. There is no public Visit increment or 755 * update API. 756 */ 757 if ( ! function_exists( 'pvc_get_visits' ) ) { 758 function pvc_get_visits( $args = [] ) { 759 global $wpdb; 760 761 $args = is_array( $args ) ? $args : []; 762 $range = Post_Views_Counter_Visits_Query::parse_range( $args ); 763 $availability = isset( Post_Views_Counter()->visits ) ? Post_Views_Counter()->visits->get_visits_availability( $range ) : [ 'readable' => false, 'read_reason' => 'schema_failed' ]; 764 $fields = isset( $args['fields'] ) && $args['fields'] === 'date=>visits' ? 'date=>visits' : 'visits'; 765 766 if ( $range === null || empty( $availability['readable'] ) ) 767 return $fields === 'date=>visits' ? [ 'values' => [], 'availability' => $availability ] : null; 768 769 // daily keys are fixed-width Ymd strings, so the (type, period) key serves the range 770 $where = [ 'pvc.`type` = 0', 'pvc.`period` BETWEEN %s AND %s' ]; 771 $params = [ sprintf( '%08d', $range['period_from'] ), sprintf( '%08d', $range['period_to'] ) ]; 772 773 if ( pvc_post_views_has_content_column() ) 774 $where[] = 'pvc.`content` = 0'; 775 776 $post_types = isset( $args['post_type'] ) ? array_values( array_filter( array_map( 'sanitize_key', (array) $args['post_type'] ) ) ) : []; 777 $join = ''; 778 779 if ( ! empty( $post_types ) ) { 780 $join = ' INNER JOIN `' . $wpdb->posts . '` posts ON posts.ID = pvc.id'; 781 $where[] = 'posts.post_type IN (' . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ')'; 782 $params = array_merge( $params, $post_types ); 783 } 784 785 $select = $fields === 'date=>visits' ? 'pvc.`period`, SUM(pvc.`visits`) AS post_visits' : 'SUM(pvc.`visits`)'; 786 $group = $fields === 'date=>visits' ? ' GROUP BY pvc.`period` ORDER BY pvc.`period` ASC' : ''; 787 $sql = $wpdb->prepare( 'SELECT ' . $select . ' FROM `' . $wpdb->prefix . 'post_views` pvc' . $join . ' WHERE ' . implode( ' AND ', $where ) . $group, $params ); 788 $cache_key = Post_Views_Counter_Visits_Query::get_read_cache_key( $sql ); 789 790 if ( $fields === 'date=>visits' ) { 791 $values = wp_cache_get( $cache_key, Post_Views_Counter_Visits_Query::VISITS_CACHE_GROUP ); 792 793 if ( $values === false ) { 794 $values = []; 795 796 $wpdb->last_error = ''; 797 $rows = $wpdb->get_results( $sql ); 798 799 if ( $wpdb->last_error !== '' ) 800 return [ 'values' => [], 'availability' => array_merge( $availability, [ 'readable' => false, 'read_reason' => 'database_error' ] ) ]; 801 802 foreach ( (array) $rows as $row ) 803 $values[(string) $row->period] = (int) $row->post_visits; 804 805 wp_cache_add( $cache_key, $values, Post_Views_Counter_Visits_Query::VISITS_CACHE_GROUP, absint( apply_filters( 'pvc_visits_object_cache_expire', 300 ) ) ); 806 } 807 808 return apply_filters( 'pvc_get_visits', [ 'values' => $values, 'availability' => $availability ], $args ); 809 } 810 811 $value = wp_cache_get( $cache_key, Post_Views_Counter_Visits_Query::VISITS_CACHE_GROUP ); 812 813 if ( $value === false ) { 814 $result = Post_Views_Counter_Visits_Query::get_scalar_result( $sql ); 815 816 if ( ! $result['success'] ) 817 return null; 818 819 $value = $result['value']; 820 wp_cache_add( $cache_key, $value, Post_Views_Counter_Visits_Query::VISITS_CACHE_GROUP, absint( apply_filters( 'pvc_visits_object_cache_expire', 300 ) ) ); 821 } 822 823 return (int) apply_filters( 'pvc_get_visits', (int) $value, $args, $availability ); 824 } 825 } 826 827 /** 828 * Get aggregate post Views per Visit for one derived-eligible range. 829 * 830 * @since 1.7.16 831 * 832 * @param array $args Explicit start/end and optional post_type scope. 833 * 834 * @return float|null Float zero is a stored zero; null means the range is not 835 * derived-eligible or Visits are unavailable. 836 */ 837 if ( ! function_exists( 'pvc_get_views_per_visit' ) ) { 838 function pvc_get_views_per_visit( $args ) { 839 global $wpdb; 840 841 $args = is_array( $args ) ? $args : []; 842 843 if ( ! empty( $args['post_id'] ) || ( isset( $args['content_type'] ) && $args['content_type'] !== 'post' ) ) 844 return null; 845 846 $range = Post_Views_Counter_Visits_Query::parse_range( $args ); 847 $availability = isset( Post_Views_Counter()->visits ) ? Post_Views_Counter()->visits->get_visits_availability( $range ) : [ 'derived_available' => false ]; 848 849 if ( $range === null || empty( $availability['derived_available'] ) ) 850 return null; 851 852 // daily keys are fixed-width Ymd strings, so the (type, period) key serves the range 853 $where = [ 'pvc.`type` = 0', 'pvc.`period` BETWEEN %s AND %s' ]; 854 $params = [ sprintf( '%08d', $range['period_from'] ), sprintf( '%08d', $range['period_to'] ) ]; 855 856 if ( pvc_post_views_has_content_column() ) 857 $where[] = 'pvc.`content` = 0'; 858 859 $post_types = isset( $args['post_type'] ) ? array_values( array_filter( array_map( 'sanitize_key', (array) $args['post_type'] ) ) ) : []; 860 $join = ''; 861 862 if ( ! empty( $post_types ) ) { 863 $join = ' INNER JOIN `' . $wpdb->posts . '` posts ON posts.ID = pvc.id'; 864 $where[] = 'posts.post_type IN (' . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ')'; 865 $params = array_merge( $params, $post_types ); 866 } 867 868 $sql = $wpdb->prepare( 'SELECT SUM(pvc.`count`) AS views, SUM(pvc.`visits`) AS visits FROM `' . $wpdb->prefix . 'post_views` pvc' . $join . ' WHERE ' . implode( ' AND ', $where ), $params ); 869 $cache_key = Post_Views_Counter_Visits_Query::get_read_cache_key( $sql ); 870 $row = wp_cache_get( $cache_key, Post_Views_Counter_Visits_Query::VIEWS_PER_VISIT_CACHE_GROUP ); 871 872 if ( $row === false ) { 873 $wpdb->last_error = ''; 874 $row = $wpdb->get_row( $sql, ARRAY_A ); 875 876 if ( $wpdb->last_error !== '' ) 877 return null; 878 879 $row = is_array( $row ) ? $row : [ 'views' => 0, 'visits' => 0 ]; 880 wp_cache_add( $cache_key, $row, Post_Views_Counter_Visits_Query::VIEWS_PER_VISIT_CACHE_GROUP, absint( apply_filters( 'pvc_visits_object_cache_expire', 300 ) ) ); 881 } 882 $visits = isset( $row['visits'] ) ? (int) $row['visits'] : 0; 883 884 if ( $visits === 0 ) 885 return null; 886 887 return (float) apply_filters( 'pvc_get_views_per_visit', (int) $row['views'] / $visits, $args, $availability ); 888 } 889 } 890 891 /** 621 892 * Display post views for a given post. 622 893 * … … 627 898 */ 628 899 if ( ! function_exists( 'pvc_post_views' ) ) { 629 function pvc_post_views( $post_id = 0, $display = true, $period = '' ) {900 function pvc_post_views( $post_id = 0, $display = true, $period = '', $args = [] ) { 630 901 // get all data 631 902 $post_id = (int) ( empty( $post_id ) ? get_the_ID() : $post_id ); 632 633 // get display options634 903 $options = Post_Views_Counter()->options['display']; 635 636 // get post views 637 $views = pvc_get_post_views( $post_id, $period !== '' ? $period : $options['display_period'] ); 638 639 // use number format? 640 $views = $options['use_format'] ? number_format_i18n( $views ) : $views; 641 642 // container class 643 $class = apply_filters( 'pvc_post_views_class', 'post-views content-post post-' . $post_id . ' entry-meta', $post_id ); 644 645 // dynamic loading? 646 $class .= $options['dynamic_loading'] === true ? ' load-dynamic' : ' load-static'; 647 648 // prepare display 649 $label = apply_filters( 'pvc_post_views_label', ( function_exists( 'icl_t' ) ? icl_t( 'Post Views Counter', 'Post Views Label', $options['label'] ) : $options['label'] ), $post_id ); 650 651 // add dashicons class if needed 652 $icon_class = strpos( $options['icon_class'], 'dashicons' ) === false ? $options['icon_class'] : 'dashicons ' . $options['icon_class']; 653 654 // prepare icon output 655 $icon = apply_filters( 'pvc_post_views_icon', '<span class="post-views-icon ' . esc_attr( $icon_class ) . '"></span> ', $post_id ); 656 657 // final views 658 $views = apply_filters( 'pvc_post_views_number_format', $views, $post_id ); 659 660 $html = apply_filters( 661 'pvc_post_views_html', 662 '<div class="' . esc_attr( $class ) . '" data-pvc-type="post" data-pvc-id="' . esc_attr( $post_id ) . '"> 663 ' . ( $options['display_style']['icon'] ? $icon : '' ) 664 . ( $options['display_style']['text'] ? '<span class="post-views-label">' . esc_html( $label ) . '</span> ' : '' ) 665 . '<span class="post-views-count">' . $views . '</span> 666 </div>', 667 $post_id, 668 $views, 669 $label, 670 $icon 671 ); 904 $args = is_array( $args ) ? $args : []; 905 $format_present = array_key_exists( 'format', $args ); 906 $format = $format_present ? $args['format'] : null; 907 $resolved_period = is_scalar( $period ) ? sanitize_key( $period !== '' ? (string) $period : $options['display_period'] ) : ''; 908 $frontend = Post_Views_Counter()->frontend; 909 910 if ( $format_present ) { 911 if ( ! is_scalar( $format ) ) 912 $html = ''; 913 else { 914 // the format places the icon itself with %%icon%%, so the Views token 915 // renders the count alone, whatever the Display Style, and resolves no 916 // icon it would never draw; its hidden label is left out when the 917 // format supplies words of its own 918 $views_token_renderer = static function ( $format_has_text = false ) use ( $frontend, $post_id, $resolved_period ) { 919 return $frontend->render_metric_span( 920 'views', 921 $post_id, 922 'post', 923 $resolved_period, 924 [ 925 'force_sr_label' => true, 926 'omit_label' => (bool) $format_has_text, 927 'icon' => '' 928 ] 929 ); 930 }; 931 $icon_token_renderer = static function () use ( $frontend, $post_id ) { 932 return $frontend->get_counter_icon( 'views', $post_id, 'post', 'pvc_post_views_icon' ); 933 }; 934 $html = $frontend->render_template( (string) $format, $post_id, 'post', $resolved_period, $views_token_renderer, $icon_token_renderer ); 935 } 936 } else { 937 $html = $frontend->render_counter( 938 [ 'views' ], 939 $post_id, 940 'post', 941 $resolved_period, 942 [ 943 'metric_args' => [ 944 'views' => [ 'html_filter' => 'pvc_post_views_html' ] 945 ] 946 ] 947 ); 948 } 672 949 673 950 if ( $display ) 674 echo wp_kses _post( $html);951 echo wp_kses( $html, Post_Views_Counter()->functions->get_counter_allowed_html() ); 675 952 else 676 953 return $html; … … 896 1173 $pvc->counter->add_to_queue( $post_id ); 897 1174 else 898 $pvc->counter->check_post( $post_id );1175 $pvc->counter->check_post( $post_id, [], true ); 899 1176 900 1177 return true; -
post-views-counter/tags/1.8.0/js/admin-columns.js
r3452736 r3734102 1 1 ;(function($, window, document){ 2 !function($){if(void 0!==$){var a=null, e=null;if("undefined"!=typeof pvcColumnModal){var t=function(a){var e=$(".pvc-modal-tab");e.prop("disabled",a),a?e.addClass("pvc-tab-disabled"):e.removeClass("pvc-tab-disabled");var t=$(".pvc-modal-nav a");a?t.each(function(){$(this).addClass("pvc-temp-disabled pvc-disabled").attr("aria-disabled","true")}):$(".pvc-modal-nav a.pvc-temp-disabled").each(function(){$(this).removeClass("pvc-temp-disabled pvc-disabled").removeAttr("aria-disabled")})},o=function(a,e){var o=$(".pvc-modal-chart-container");o.addClass("loading"),o.find(".spinner").addClass("is-active"),t(!0),$.ajax({url:pvcColumnModal.ajaxURL,type:"POST",dataType:"json",data:{action:"pvc_column_chart",nonce:pvcColumnModal.nonce,post_id:a,period:e},success:function(a){a.success?n(a.data):d(a.data.message||pvcColumnModal.i18n.error)},error:function(){d(pvcColumnModal.i18n.error)},complete:function(){t(!1),o.removeClass("loading"),o.find(".spinner").removeClass("is-active")}})},n=function(e){var t=document.getElementById("pvc-modal-chart");if(t){a&&(a.destroy(),a=null),$(".pvc-modal-error").remove(),$(t).show(),$(".pvc-modal-views-label").text(pvcColumnModal.i18n.summary),$(".pvc-modal-count").text(e.total_views.toLocaleString()),$(".pvc-modal-dates").html(e.dates_html);var o={type:"line",data:e.data,options:{maintainAspectRatio:!1,responsive:!0,plugins:{legend:{display:!1},tooltip:{callbacks:{title:function(a){return e.data.dates[a[0].dataIndex]},label:function(a){var e=a.parsed.y,t=1===e?pvcColumnModal.i18n.view:pvcColumnModal.i18n.views;return"".concat(e.toLocaleString()," ").concat(t)}}}},scales:{x:{display:!0,grid:{display:!1}},y:{display:!0,beginAtZero:!0,ticks:{precision:0},grid:{color:"rgba(0, 0, 0, 0.05)"}}}}};e.design&&o.data.datasets.forEach(function(a){Object.assign(a,e.design),a.tension=.4}),a=new Chart(t.getContext("2d"),o),$(".pvc-modal-content-middle").show()}},d=function(e){a&&(a.destroy(),a=null),$(".pvc-modal-summary").text(""),$(".pvc-modal-dates").html(""),$(".pvc-modal-content-middle").hide();var t=$(".pvc-modal-chart-container");t.removeClass("loading"),t.find(".spinner").removeClass("is-active"),$(".pvc-modal-error").remove(),t.before('<p class="pvc-modal-error">'.concat(e,"</p>")),t.find("canvas").hide()};$(function(){0!==$("#pvc-chart-modal").length&&"undefined"!=typeof MicroModal&&(MicroModal.init({disableScroll:!0,awaitCloseAnimation:!0}),1)&&($(document).on("click",".pvc-view-chart",function(n){n.preventDefault();var d=$(n.currentTarget),l=d.data("post-id"),i=d.data("post-title");l&&function(a,o){if(!a)return!1;e=a,$("#pvc-modal-title").text(o);var n=$(".pvc-modal-chart-container");return n.addClass("loading"),n.find(".spinner").addClass("is-active"),t(!0),$(".pvc-modal-views-label").text(""),$(".pvc-modal-count").text(""),$(".pvc-modal-dates").html(""),$(".pvc-modal-content-middle").hide(),!0}(l,i)&&"undefined"!=typeof MicroModal&&MicroModal.show("pvc-chart-modal",{onShow:function(){e&&o(e,"")},onClose:function(){a&&(a.destroy(),a=null),e=null,function(){$("#pvc-modal-title").text(""),$(".pvc-modal-views-label").text(""),$(".pvc-modal-count").text(""),$(".pvc-modal-dates").html(""),$(".pvc-modal-content-middle").hide();var a=$(".pvc-modal-chart-container");a.removeClass("loading"),a.find(".spinner").removeClass("is-active"),$(".pvc-modal-error").remove()}()},disableScroll:!0,awaitCloseAnimation:!0})}),$(document).on("click",".pvc-modal-nav-prev, .pvc-modal-nav-next",function(a){a.preventDefault();var t=$(a.currentTarget);if(!t.hasClass("pvc-disabled")){var n=t.data("period");n&&e&&o(e,n)}}))})}}}(jQuery);2 !function($){if(void 0!==$){var a=null,t=null,e="",o=null,n=null,l="";if("undefined"!=typeof pvcColumnModal){var c="pro"===pvcColumnModal.modalOwner,d=function(a){$(".pvc-modal-tab.pvc-pro").addClass("pvc-tab-disabled");var t=$(".pvc-modal-nav a");a?t.each(function(){$(this).addClass("pvc-temp-disabled pvc-disabled").attr("aria-disabled","true")}):$(".pvc-modal-nav a.pvc-temp-disabled").each(function(){$(this).removeClass("pvc-temp-disabled pvc-disabled").removeAttr("aria-disabled")})},r=function(a){$(".pvc-modal-status").text(a||"")},i=function(){$(".pvc-modal-count-views").text("")},v=function(a,t){n&&(n.abort(),n=null);var o=$(".pvc-modal-chart-container");e=t||"",o.addClass("loading"),o.find(".spinner").addClass("is-active"),$("#pvc-modal-chart-panel").attr("aria-busy","true"),r(pvcColumnModal.i18n.loading),d(!0),n=$.ajax({url:pvcColumnModal.ajaxURL,type:"POST",dataType:"json",data:{action:"pvc_column_chart",nonce:pvcColumnModal.nonce,post_id:a,period:t},success:function(a){a.success?s(a.data):p(a.data.message||pvcColumnModal.i18n.error)},error:function(a,t){"abort"!==t&&p(pvcColumnModal.i18n.error)},complete:function(){n=null,d(!1),function(){if(l){var a=l;l="";var t=document.querySelector("a.pvc-modal-nav-".concat(a))||document.querySelector(".pvc-modal-nav a")||document.querySelector(".pvc-modal-tab.active");t&&"function"==typeof t.focus&&t.focus()}}(),o.removeClass("loading"),o.find(".spinner").removeClass("is-active"),$("#pvc-modal-chart-panel").attr("aria-busy","false")}})},s=function(t){var o=document.getElementById("pvc-modal-chart");if(o){a&&(a.destroy(),a=null),$(".pvc-modal-error").remove(),r(""),$(o).show(),e=t.period||e,function(a){var t=a.totals||{};$(".pvc-modal-count-views").text(Number(t.views||0).toLocaleString())}(t),$(".pvc-modal-dates").html(t.dates_html);var n={type:"line",data:t.data,options:{maintainAspectRatio:!1,responsive:!0,interaction:{intersect:!1,mode:"index"},plugins:{legend:{display:!1},tooltip:{callbacks:{title:function(a){return t.data.dates[a[0].dataIndex]},label:function(a){return"".concat(a.dataset.label,": ").concat(function(a){var t=a.dataset.formatted;return Array.isArray(t)&&"string"==typeof t[a.dataIndex]?t[a.dataIndex]:a.formattedValue}(a))}}}},scales:{x:{display:!0,grid:{display:!1}},y:{display:!0,beginAtZero:!0,ticks:{precision:0},grid:{color:"rgba(0, 0, 0, 0.05)"}}}}};n.data.datasets.forEach(function(a){a.tension=.4}),a=new Chart(o.getContext("2d"),n),$(".pvc-modal-content-middle").show()}},p=function(t){a&&(a.destroy(),a=null),i(),$(".pvc-modal-dates").html(""),l="",$(".pvc-modal-content-middle").hide();var e=$(".pvc-modal-chart-container");e.removeClass("loading"),e.find(".spinner").removeClass("is-active"),$(".pvc-modal-error").remove();var o=$("<p>",{class:"pvc-modal-error",role:"alert"}).text(t);o.append(" ").append($("<button>",{type:"button",class:"button-link pvc-modal-retry"}).text(pvcColumnModal.i18n.retry)),e.before(o),r(""),e.find("canvas").hide()};$(function(){if(!c&&0!==$("#pvc-chart-modal").length&&"undefined"!=typeof MicroModal&&(MicroModal.init({disableScroll:!0,awaitCloseAnimation:!0}),1)){var s=$(document);s.off("click.pvcCoreModal",".pvc-view-chart").on("click.pvcCoreModal",".pvc-view-chart",function(c){c.preventDefault();var s=$(c.currentTarget),p=s.data("post-id"),u=s.data("post-title");p&&function(a,n,c){if(!a)return!1;t=a,o=c||null,e="",l="",$("#pvc-modal-title").text(n);var v=$(".pvc-modal-chart-container");return v.addClass("loading"),v.find(".spinner").addClass("is-active"),$("#pvc-modal-chart-panel").attr("aria-busy","true"),d(!0),i(),$(".pvc-modal-dates").html(""),r(pvcColumnModal.i18n.loading),$(".pvc-modal-content-middle").hide(),!0}(p,u,c.currentTarget)&&"undefined"!=typeof MicroModal&&MicroModal.show("pvc-chart-modal",{onShow:function(){t&&v(t,"")},onClose:function(){l="",n&&(n.abort(),n=null),a&&(a.destroy(),a=null),t=null,e="",function(){$("#pvc-modal-title").text(""),i(),$(".pvc-modal-dates").html(""),$(".pvc-modal-content-middle").hide();var a=$(".pvc-modal-chart-container");a.removeClass("loading"),a.find(".spinner").removeClass("is-active"),$(".pvc-modal-error").remove(),r("")}(),o&&document.body.contains(o)&&o.focus(),o=null},disableScroll:!0,awaitCloseAnimation:!0})}),s.off("click.pvcCoreModal",".pvc-modal-retry").on("click.pvcCoreModal",".pvc-modal-retry",function(a){a.preventDefault(),t&&v(t,e)}),s.off("click.pvcCoreModal",".pvc-modal-nav-prev, .pvc-modal-nav-next").on("click.pvcCoreModal",".pvc-modal-nav-prev, .pvc-modal-nav-next",function(a){a.preventDefault();var e=$(a.currentTarget);if(!n&&!e.hasClass("pvc-disabled")&&"true"!==e.attr("aria-disabled")){var o=e.data("period");o&&t&&(l=e.hasClass("pvc-modal-nav-next")?"next":"prev",v(t,o))}})}})}}}(jQuery); 3 3 4 4 })(jQuery, window, document); -
post-views-counter/tags/1.8.0/js/admin-dashboard.js
r3578455 r3734102 1 1 ;(function($, window, document){ 2 function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,o)}return n}function t(t){for(var o=1;o<arguments.length;o++){var r=null!=arguments[o]?arguments[o]:{};o%2?e(Object(r),!0).forEach(function(e){n(t,e,r[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):e(Object(r)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))})}return t}function n(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=o(e)||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t);if("object"!=o(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==o(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}!function($){var e=["#pvc-dashboard-accordion"],n={weekly:"this_week",monthly:"this_month",yearly:"this_year"},r={loadError:window.pvcArgs&&window.pvcArgs.i18n&&window.pvcArgs.i18n.loadError?window.pvcArgs.i18n.loadError:"Failed to load this widget.",retry:window.pvcArgs&&window.pvcArgs.i18n&&window.pvcArgs.i18n.retry?window.pvcArgs.i18n.retry:"Retry"},a={},i={},s=$({});"function"!=typeof $.pvcAjaxQueue&&($.pvcAjaxQueue=function(e){var t,n=$.Deferred(),o=n.promise(),r=function(o){(t=$.ajax(e)).done(n.resolve).fail(n.reject).then(o,o)};return s.queue(r),o.abort=function(a){if(t)return t.abort(a);var i=s.queue(),d=$.inArray(r,i);return d>-1&&i.splice(d,1),n.rejectWith(e.context||e,[o,a,""]),o},o});var d=function(e){return e&&e.id?e.id.replace(/^pvc-/,""):""},c=function(e){return"string"==typeof e?{period:e}:e&&"object"===o(e)?t({},e):{}},l=function(e){return i[e]||(i[e]={loaded:!1,loading:!1,lastOptions:{},lastRequestId:0,activeRequest:null,error:null,lastResponse:null,promise:null}),i[e]},p=function(e,t){e&&0!==e.length&&(e.toggleClass("loading",t),e.find(".spinner").toggleClass("is-active",t))},u=function(e){if(!e||0===e.length)return $();var t=e.find(".pvc-dashboard-message").first();if(0===t.length){var n=e.find(".pvc-data-container").first();if(n.length>0){t=$('<div class="pvc-dashboard-message" aria-live="polite"></div>');var o=n.find(".spinner").first();o.length>0?o.before(t):n.append(t)}}return t},v=function(e){e&&0!==e.length&&(e.removeClass("pvc-has-error"),u(e).empty())},f=function(e,t){if(e&&0!==e.length&&!1!==t){var n=e.find(".pvc-date-nav").first();0===n.length&&(n=e.find(".pvc-months").first()),n.length>0&&(n[0].innerHTML=t)}},g=function(e){"function"==typeof window.pvcUpdateUserOptions&&window.pvcUpdateUserOptions(e)},w=function(e,n){var o=t({},n);delete o.dates,delete o.html,delete o.design,window.dispatchEvent(new CustomEvent(e,{detail:o}))},h=function(e,t){a[e]=t,l(e)},b=function(e){return!!a[e]},m=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],i=function(e){return a[e]||null}(e),s=l(e),d=function(e){var t=document.getElementById("pvc-".concat(e));return t?$(t).find(".pvc-dashboard-container").first():$()}(e);if(!i||0===d.length)return null;if(s.loading&&!o)return s.promise||s.activeRequest;if(s.loaded&&!o)return s.promise||s.lastResponse;var f=s.lastRequestId+1,g=t(t({},s.lastOptions),c(n)),w={container:d,widgetId:e,isInitialLoad:!s.loaded};s.lastRequestId=f,s.loading=!0,s.lastOptions=g,s.error=null,s.promise=null,v(d),p(d,!0),s.activeRequest&&"function"==typeof s.activeRequest.abort&&s.activeRequest.abort("pvc-dashboard-refresh");var h=$.ajax({url:i.ajaxURL||pvcArgs.ajaxURL,type:"POST",dataType:"json",data:i.buildRequest(g,w,s)});return s.activeRequest=h,s.promise=h,h.done(function(e){s.lastRequestId===f&&(s.loaded=!0,s.loading=!1,s.error=null,s.activeRequest=null,s.lastResponse=e,v(d),p(d,!1),i.render(e,w,g,s))}),h.fail(function(t,n,o){s.lastRequestId===f&&(s.loading=!1,s.activeRequest=null,s.error={statusText:n,errorThrown:o},p(d,!1),"abort"!==n&&function(e,t,n){if(e&&0!==e.length){var o=['<div class="pvc-dashboard-error" role="alert">','<div class="pvc-dashboard-error-message">','<span class="pvc-dashboard-error-text">',n,"</span>","</div>",'<button type="button" class="button button-secondary pvc-dashboard-retry" data-widget-id="',t,'">',r.retry,"</button>","</div>"].join("");e.addClass("pvc-has-error"),u(e).html(o)}}(d,e,i.errorMessage||r.loadError))}),h},y=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=l(e);return n.loaded||n.loading?n.promise||n.activeRequest||n.lastResponse||null:m(e,t,!1)},C=function(e){return m(e,arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},!0)},j=function(e){var t=$(e);0!==t.length&&t.find(".pvc-accordion-item:not(.pvc-collapsed)").each(function(e,t){var n=d(t);n&&b(n)&&y(n)})},O=function(e){var t=e.target.closest(".pvc-dashboard-retry");if(t){var o=t.dataset.widgetId;o&&b(o)&&(e.preventDefault(),e.stopImmediatePropagation(),C(o))}else{var r=e.target.closest(".pvc-date-select .button");if(r){var a=r.closest(".pvc-accordion-item"),i=d(a);i&&b(i)&&(e.preventDefault(),e.stopImmediatePropagation(),function(e){var t=String($(e).data("datenav")),o=$(e).closest(".pvc-date-select"),r=$(e).closest(".pvc-accordion-item"),a=d(r[0]);if(a&&b(a)){var i=o.find(".button-primary").first(),s=i.length>0?String(i.data("datenav")):"";if(o.find(".button").each(function(e,n){String($(n).data("datenav"))===t?$(n).removeClass("button-secondary").addClass("button-primary").blur():$(n).removeClass("button-primary").addClass("button-secondary")}),t!==s){C(a,{datenav:t,period:n[t]||""});var c=a.replace(/^pvc-/,""),l={datenav:{}};l.datenav[c]=t,g(l)}}}(r))}else{var s=e.target.closest(".pvc-date-nav .prev, .pvc-date-nav .next");if(s){var c=s.closest(".pvc-accordion-item"),l=d(c);l&&b(l)&&(e.preventDefault(),e.stopImmediatePropagation(),C(l,{period:s.dataset.date}))}else{var p=e.target.closest(".pvc-accordion-header");if(p){var u,v=p.closest(".pvc-accordion-item"),f=d(v);if(f&&b(f))e.preventDefault(),e.stopImmediatePropagation(),v.classList.toggle("pvc-collapsed"),g({menu_items:(u={},["#pvc-dashboard-accordion .pvc-accordion-item","#pvc-dashboard-traffic-accordion .pvc-accordion-item"].forEach(function(e){$(e).each(function(e,t){var n=$(t).attr("id");void 0!==n&&(u[n.replace("pvc-","")]=$(t).hasClass("pvc-collapsed"))})}),u)}),v.classList.contains("pvc-collapsed")||y(f)}}}}},R=window.pvcDashboard||{};Object.assign(R,{registerWidget:h,ensureWidgetLoaded:y,refreshWidget:C,loadExpandedWidgets:j,isWidgetLoaded:function(e){return l(e).loaded},isWidgetRegistered:b}),window.pvcDashboard=R,window.pvcDashboardEventsBound||(window.pvcDashboardEventsBound=!0,document.addEventListener("click",O,!0)),window.addEventListener("load",function(){j(e[0])}),window.dispatchEvent(new CustomEvent("pvc-dashboard-controller-ready",{detail:R})),window.pvcUpdateUserOptions=function(e){$.pvcAjaxQueue({url:pvcArgs.ajaxURL,type:"POST",dataType:"json",data:{action:"pvc_dashboard_user_options",nonce:pvcArgs.nonceUser,options:e},success:function(){}})},window.pvcUpdateConfig=function(e,t){return e.data=t.data,e.options.plugins.tooltip={callbacks:{title:function(e){return t.data.dates[e[0].dataIndex]}}},$.each(e.data.datasets,function(e,n){n.fill=t.design.fill,n.tension=.4,n.borderColor=t.design.borderColor,n.backgroundColor=t.design.backgroundColor,n.borderWidth=t.design.borderWidth,n.borderDash=t.design.borderDash,n.pointBorderColor=t.design.pointBorderColor,n.pointBackgroundColor=t.design.pointBackgroundColor,n.pointBorderWidth=t.design.pointBorderWidth}),e},h("post-views",{buildRequest:function(e){return{action:"pvc_dashboard_post_views_chart",nonce:pvcArgs.nonce,period:e.period||"",datenav:e.datenav||"",lang:pvcArgs.lang?pvcArgs.lang:""}},render:function(e,t,n,o){if(f(t.container,e.dates),t.isInitialLoad||!window.postViewsChart){var r={type:"line",options:{maintainAspectRatio:!1,responsive:!0,plugins:{legend:{display:!0,position:"bottom",align:"center",fullSize:!0,onHover:function(e){e.native.target.style.cursor="pointer"},onLeave:function(e){e.native.target.style.cursor="default"},onClick:function(e,t,n){var o=t.datasetIndex,r=n.chart,a=r.getDatasetMeta(o);a.hidden=!!r.isDatasetVisible(o),r.update(),window.pvcUpdateUserOptions({post_type:r.data.datasets[o].post_type,hidden:a.hidden})},labels:{boxWidth:8,boxHeight:8,font:{size:13,weight:"normal",family:"'-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Oxygen-Sans', 'Ubuntu', 'Cantarell', 'Helvetica Neue', 'sans-serif'"},padding:10,usePointStyle:!1,textAlign:"center"}}},scales:{x:{display:!0,title:{display:!1}},y:{display:!0,grace:0,beginAtZero:!0,title:{display:!1},ticks:{precision:0,maxTicksLimit:12}}},hover:{mode:"label"}}};return r=window.pvcUpdateConfig(r,e),window.postViewsChart=new Chart(document.getElementById("pvc-post-views-chart").getContext("2d"),r),void w("pvc-dashboard-widget-loaded",e)}window.postViewsChart.config=window.pvcUpdateConfig(window.postViewsChart.config,e),window.postViewsChart.update(),w("pvc-dashboard-widget-loaded",e)},errorMessage:r.loadError}),h("post-most-viewed",{buildRequest:function(e){return{action:"pvc_dashboard_post_most_viewed",nonce:pvcArgs.nonce,period:e.period||"",datenav:e.datenav||"",lang:pvcArgs.lang?pvcArgs.lang:""}},render:function(e,t){f(t.container,e.dates),t.container.find("#pvc-post-most-viewed-content").html(e.html),w("pvc-dashboard-widget-loaded",e)},errorMessage:r.loadError}),window.pvcUpdatePostViewsWidget=function(){C("post-views",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))},window.pvcUpdatePostMostViewedWidget=function(){C("post-most-viewed",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))},window.pvcLoadPostViewsData=function(){C("post-views",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))},window.pvcLoadPostMostViewedData=function(){C("post-most-viewed",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))}}(jQuery);2 function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function t(t){for(var r=1;r<arguments.length;r++){var i=null!=arguments[r]?arguments[r]:{};r%2?e(Object(i),!0).forEach(function(e){n(t,e,i[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(i)):e(Object(i)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(i,e))})}return t}function n(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=r(e)||!e)return e;var n;if("undefined"!=typeof Symbol&&void 0!==(n=e[Symbol.toPrimitive])){var i=n.call(e,t);if("object"!=r(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==r(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}!function($){var e=["#pvc-dashboard-accordion"],n={weekly:"this_week",monthly:"this_month",yearly:"this_year"},i={loadError:window.pvcArgs&&window.pvcArgs.i18n&&window.pvcArgs.i18n.loadError?window.pvcArgs.i18n.loadError:"Failed to load this widget.",retry:window.pvcArgs&&window.pvcArgs.i18n&&window.pvcArgs.i18n.retry?window.pvcArgs.i18n.retry:"Retry"},a={},o={},s=$({});"function"!=typeof $.pvcAjaxQueue&&($.pvcAjaxQueue=function(e){var t,n=$.Deferred(),r=n.promise(),i=function(r){(t=$.ajax(e)).done(n.resolve).fail(n.reject).then(r,r)};return s.queue(i),r.abort=function(a){if(t)return t.abort(a);var o=s.queue(),d=$.inArray(i,o);return d>-1&&o.splice(d,1),n.rejectWith(e.context||e,[r,a,""]),r},r});var d=function(e){return e&&e.id?e.id.replace(/^pvc-/,""):""},c=function(e){return"string"==typeof e?{period:e}:e&&"object"===r(e)?t({},e):{}},l=function(e){return o[e]||(o[e]={loaded:!1,loading:!1,lastOptions:{},lastRequestId:0,activeRequest:null,error:null,lastResponse:null,promise:null}),o[e]},p=function(e,t){e&&0!==e.length&&(e.toggleClass("loading",t),e.find(".spinner").toggleClass("is-active",t))},v=function(e){if(!e||0===e.length)return $();var t=e.find(".pvc-dashboard-message").first();if(0===t.length){var n=e.find(".pvc-data-container").first();if(n.length>0){t=$('<div class="pvc-dashboard-message" aria-live="polite"></div>');var r=n.find(".spinner").first();r.length>0?r.before(t):n.append(t)}}return t},u=function(e){e&&0!==e.length&&(e.removeClass("pvc-has-error"),v(e).empty())},f=function(e,t){if(e&&0!==e.length&&!1!==t){var n=e.find(".pvc-date-nav").first();0===n.length&&(n=e.find(".pvc-months").first()),n.length>0&&(n[0].innerHTML=t)}},g=function(e){"function"==typeof window.pvcUpdateUserOptions&&window.pvcUpdateUserOptions(e)},h=function(e,n){var r=t({},n);delete r.dates,delete r.html,delete r.design,window.dispatchEvent(new CustomEvent(e,{detail:r}))},w=function(e,t){a[e]=t,l(e)},b=function(e){return!!a[e]},m=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],o=function(e){return a[e]||null}(e),s=l(e),d=function(e){var t=document.getElementById("pvc-".concat(e));return t?$(t).find(".pvc-dashboard-container").first():$()}(e);if(!o||0===d.length)return null;if(s.loading&&!r)return s.promise||s.activeRequest;if(s.loaded&&!r)return s.promise||s.lastResponse;var f=s.lastRequestId+1,g=t(t({},s.lastOptions),c(n)),h={container:d,widgetId:e,isInitialLoad:!s.loaded};s.lastRequestId=f,s.loading=!0,s.lastOptions=g,s.error=null,s.promise=null,u(d),p(d,!0),s.activeRequest&&"function"==typeof s.activeRequest.abort&&s.activeRequest.abort("pvc-dashboard-refresh");var w=$.ajax({url:o.ajaxURL||pvcArgs.ajaxURL,type:"POST",dataType:"json",data:o.buildRequest(g,h,s)});return s.activeRequest=w,s.promise=w,w.done(function(e){s.lastRequestId===f&&(s.loaded=!0,s.loading=!1,s.error=null,s.activeRequest=null,s.lastResponse=e,u(d),p(d,!1),o.render(e,h,g,s))}),w.fail(function(t,n,r){s.lastRequestId===f&&(s.loading=!1,s.activeRequest=null,s.error={statusText:n,errorThrown:r},p(d,!1),"abort"!==n&&function(e,t,n){if(e&&0!==e.length){var r=['<div class="pvc-dashboard-error" role="alert">','<div class="pvc-dashboard-error-message">','<span class="pvc-dashboard-error-text">',n,"</span>","</div>",'<button type="button" class="button button-secondary pvc-dashboard-retry" data-widget-id="',t,'">',i.retry,"</button>","</div>"].join("");e.addClass("pvc-has-error"),v(e).html(r)}}(d,e,o.errorMessage||i.loadError))}),w},y=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=l(e);return n.loaded||n.loading?n.promise||n.activeRequest||n.lastResponse||null:m(e,t,!1)},x=function(e){return m(e,arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},!0)},C=function(e){var t=$(e);0!==t.length&&t.find(".pvc-accordion-item:not(.pvc-collapsed)").each(function(e,t){var n=d(t);n&&b(n)&&y(n)})},A=function(e){var t=e.target.closest(".pvc-dashboard-retry");if(t){var r=t.dataset.widgetId;r&&b(r)&&(e.preventDefault(),e.stopImmediatePropagation(),x(r))}else{var i=e.target.closest(".pvc-date-select .button");if(i){var a=i.closest(".pvc-accordion-item"),o=d(a);o&&b(o)&&(e.preventDefault(),e.stopImmediatePropagation(),function(e){if(!e.disabled&&"true"!==e.getAttribute("aria-disabled")){var t=String($(e).data("datenav")),r=$(e).closest(".pvc-date-select"),i=$(e).closest(".pvc-accordion-item"),a=d(i[0]);if(a&&b(a)){var o=r.find(".button-primary").first(),s=o.length>0?String(o.data("datenav")):"";if(r.find(".button").each(function(e,n){String($(n).data("datenav"))===t?$(n).removeClass("button-secondary").addClass("button-primary").blur():$(n).removeClass("button-primary").addClass("button-secondary")}),t!==s){x(a,{datenav:t,period:n[t]||""});var c=a.replace(/^pvc-/,""),l={datenav:{}};l.datenav[c]=t,g(l)}}}}(i))}else{var s=e.target.closest(".pvc-date-nav .prev, .pvc-date-nav .next");if(s){var c=s.closest(".pvc-accordion-item"),l=d(c);l&&b(l)&&(e.preventDefault(),e.stopImmediatePropagation(),x(l,{period:s.dataset.date}))}else{var p=e.target.closest(".pvc-accordion-header");if(p){var v,u=p.closest(".pvc-accordion-item"),f=d(u);if(f&&b(f))e.preventDefault(),e.stopImmediatePropagation(),u.classList.toggle("pvc-collapsed"),g({menu_items:(v={},["#pvc-dashboard-accordion .pvc-accordion-item","#pvc-dashboard-traffic-accordion .pvc-accordion-item"].forEach(function(e){$(e).each(function(e,t){var n=$(t).attr("id");void 0!==n&&(v[n.replace("pvc-","")]=$(t).hasClass("pvc-collapsed"))})}),v)}),u.classList.contains("pvc-collapsed")||y(f)}}}}},_={},O=["both","views","visits"],j=function(e){return _[e]||(_[e]={preferred:"",bothHidden:{}}),_[e]},E=function(e){return!!(e&&e.metric_state&&Array.isArray(e.metrics)&&e.data&&Array.isArray(e.data.datasets))},R=function(e,t){var n=j(e),r=!(!t.availability||!t.availability.readable);if(!n.preferred){var i=t.metric_state?t.metric_state.preferred:"";n.preferred=-1!==O.indexOf(i)?i:"both"}return{available:r,preferred:n.preferred,effective:r?n.preferred:"views"}},k=function(e,t,n,r){if(t&&E(n)){var i=j(e),a=R(e,n);n.data.datasets.forEach(function(e,n){e.fill="origin",e.backgroundColor=function(e,t){if("string"!=typeof e)return e;var n=e.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*[\d.]+)?\s*\)$/i);return n?"rgba(".concat(n[1],",").concat(n[2],",").concat(n[3],",").concat(t,")"):e}(e.borderColor,.1),t.setDatasetVisibility(n,function(e,t,n){return"both"===t?!!e.is_total&&!0!==n.bothHidden[e.metric]:e.metric===t&&!0!==e.dimension_hidden}(e,a.effective,i))}),t.update(),function(e,t,n){var r=e.find(".pvc-dashboard-metrics").get(0);if(r&&window.pvcMetricToggle&&"function"==typeof window.pvcMetricToggle.render){var i=r.getAttribute("data-pvc-widget")?"pvc-".concat(r.getAttribute("data-pvc-widget"),"-visits-unavailable"):"",a=t.metrics.map(function(e){var t=!1!==e.available&&("visits"!==e.key||n.available);return{metric:e.key,key:e.key,label:e.label,pressed:t&&("both"===n.effective||n.effective===e.key),disabled:!t,describedBy:t?"":i,color:e.color,dashed:!0===e.dashed}});window.pvcMetricToggle.render(r,a,{containerClasses:["pvc-dashboard-metric-buttons"]});var o=e.find("#".concat(i));o.length>0&&(n.available?o.attr("hidden","hidden").text(""):o.removeAttr("hidden").text(t.notices&&t.notices.visits_unavailable||""))}}(r,n,a),function(e,t,n,r){var i=e.find(".pvc-dashboard-legend").get(0);i&&window.pvcMetricToggle&&"function"==typeof window.pvcMetricToggle.render&&window.pvcMetricToggle.render(i,function(e,t,n){return t.data.datasets.map(function(e,t){return{dataset:e,index:t}}).filter(function(e){return"both"===n?!!e.dataset.is_total:e.dataset.metric===n}).map(function(t){return{metric:t.dataset.metric,label:t.dataset.label,datasetIndex:t.index,pressed:e.isDatasetVisible(t.index),color:t.dataset.borderColor,circle:!0}})}(t,n,r),{containerClasses:["pvc-dashboard-dataset-legend"]})}(r,t,n,a.effective)}},P=function(e,t,n){var r=t.get(0);r&&"1"!==r.dataset.pvcMetricControlsBound&&(r.dataset.pvcMetricControlsBound="1",r.addEventListener("click",function(r){var i=r.target.closest(".pvc-metric-toggle-item");if(i&&!i.disabled){var a=n();a&&a.chart&&E(a.response)&&(r.preventDefault(),r.stopImmediatePropagation(),i.closest(".pvc-dashboard-metrics")?function(e,t,n,r,i){var a=j(e),o=R(e,n);if("visits"!==i||o.available){var s="both"===o.effective?["views","visits"]:[o.effective],d="";if(-1!==s.indexOf(i)){if(1===s.length)return;d="views"===i?"visits":"views"}else d="both";if(d!==o.effective){a.bothHidden={},a.preferred=d,k(e,t,n,r);var c={};c[e]=d,g({metrics:c})}}}(e,a.chart,a.response,t,i.getAttribute("data-pvc-metric")):i.closest(".pvc-dashboard-legend")&&function(e,t,n,r,i){var a=n.data.datasets[i];if(a){var o=j(e),s=R(e,n),d=!t.isDatasetVisible(i);if("both"===s.effective)o.bothHidden[a.metric]=!d;else{var c=function(e){for(var t=["post_type","content_type","taxonomy"],n=0;n<t.length;n++)if(e[t[n]])return{key:t[n],value:e[t[n]]};return null}(a);if(n.data.datasets.forEach(function(e){c&&e[c.key]===c.value&&(e.dimension_hidden=!d)}),c){var l={hidden:!d};l[c.key]=c.value,g(l)}}k(e,t,n,r)}}(e,a.chart,a.response,t,parseInt(i.getAttribute("data-pvc-dataset-index"),10)))}}))},I=window.pvcDashboard||{};Object.assign(I,{registerWidget:w,ensureWidgetLoaded:y,refreshWidget:x,loadExpandedWidgets:C,isWidgetLoaded:function(e){return l(e).loaded},isWidgetRegistered:b,metrics:{version:1,isPairedResponse:E,applyMetricMode:k,bindMetricControls:P,getMetricState:j}}),window.pvcDashboard=I,window.pvcDashboardEventsBound||(window.pvcDashboardEventsBound=!0,document.addEventListener("click",A,!0));var D={up:"up",down:"down",mixed:"neutral",same:"neutral"},S=["locked","not_enough_data","no_insights"];window.addEventListener("pvc-dashboard-widget-loaded",function(e){return function(e){if(e&&"string"==typeof e.widget){var t=document.getElementById("pvc-".concat(e.widget,"-widget-insights"));t&&(t.textContent="",(Array.isArray(e.insight_notices)?e.insight_notices.slice(0,4):[]).forEach(function(e){if(e&&"string"==typeof e.text&&""!==e.text){var n=document.createElement("p"),r=["pvc-widget-insight"];if("string"==typeof e.state){if(!S.includes(e.state))return;if(r.push("pvc-widget-insight-state","locked"===e.state?"pvc-widget-insight-locked":"pvc-widget-insight-neutral"),"locked"===e.state&&"string"==typeof e.url&&/^https?:\/\//.test(e.url)){var i=document.createElement("a");i.setAttribute("href",e.url),i.setAttribute("target","_blank"),i.setAttribute("rel","noopener noreferrer"),"string"==typeof e.link_text&&""!==e.link_text?(n.appendChild(document.createTextNode("".concat(e.text," "))),i.textContent=e.link_text):i.textContent=e.text,n.appendChild(i)}else n.textContent=e.text}else r.push("pvc-widget-insight-".concat(D[e.direction]||"neutral")),n.textContent=e.text;n.className=r.join(" "),t.appendChild(n)}}),t.hidden=0===t.childNodes.length)}}(e.detail)}),window.addEventListener("load",function(){C(e[0])}),window.dispatchEvent(new CustomEvent("pvc-dashboard-controller-ready",{detail:I})),window.pvcUpdateUserOptions=function(e){$.pvcAjaxQueue({url:pvcArgs.ajaxURL,type:"POST",dataType:"json",data:{action:"pvc_dashboard_user_options",nonce:pvcArgs.nonceUser,options:e},success:function(){}})},window.pvcUpdateConfig=function(e,t){e.data=t.data,e.options.plugins.tooltip={callbacks:{title:function(e){return t.data.dates[e[0].dataIndex]},label:function(e){var t=e.dataset.formatted,n=Array.isArray(t)&&"string"==typeof t[e.dataIndex]?t[e.dataIndex]:e.formattedValue;return e.dataset.label?"".concat(e.dataset.label,": ").concat(n):n}}};var n=t.design||{},r=["fill","tension","borderColor","backgroundColor","borderWidth","borderDash","pointBorderColor","pointBackgroundColor","pointBorderWidth"];return $.each(e.data.datasets,function(e,t){r.forEach(function(e){Object.prototype.hasOwnProperty.call(n,e)&&(Object.prototype.hasOwnProperty.call(t,e)||(t[e]=n[e]))}),Object.prototype.hasOwnProperty.call(t,"tension")||(t.tension=.4)}),e};w("post-views",{buildRequest:function(e){return{action:"pvc_dashboard_post_views_chart",nonce:pvcArgs.nonce,period:e.period||"",datenav:e.datenav||"",lang:pvcArgs.lang?pvcArgs.lang:""}},render:function(e,t,n,r){f(t.container,e.dates),function(e,t){var n=e[0]&&e[0].querySelector(".pvc-dashboard-headline .pvc-data-count");if(n){var r=t&&t.summary;n.textContent=r&&"string"==typeof r.views_html&&""!==r.views_html.trim()?r.views_html:""}}(t.container,e);var i=E(e);if(t.isInitialLoad||!window.postViewsChart){var a={type:"line",options:{maintainAspectRatio:!1,responsive:!0,interaction:{intersect:!1,mode:"index"},plugins:{legend:{display:!i,position:"bottom",align:"center",fullSize:!0,onHover:function(e){e.native.target.style.cursor="pointer"},onLeave:function(e){e.native.target.style.cursor="default"},onClick:function(e,t,n){var r=t.datasetIndex,i=n.chart,a=i.getDatasetMeta(r);a.hidden=!!i.isDatasetVisible(r),i.update(),window.pvcUpdateUserOptions({post_type:i.data.datasets[r].post_type,hidden:a.hidden})},labels:{boxWidth:8,boxHeight:8,font:{size:13,weight:"normal",family:"'-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Oxygen-Sans', 'Ubuntu', 'Cantarell', 'Helvetica Neue', 'sans-serif'"},padding:10,usePointStyle:!1,textAlign:"center"}}},scales:{x:{display:!0,title:{display:!1}},y:{display:!0,grace:0,beginAtZero:!0,title:{display:!1},ticks:{precision:0,maxTicksLimit:12}}}}};return a=window.pvcUpdateConfig(a,e),window.postViewsChart=new Chart(document.getElementById("pvc-post-views-chart").getContext("2d"),a),i&&(P("post-views",t.container,function(){return{chart:window.postViewsChart,response:l("post-views").lastResponse}}),k("post-views",window.postViewsChart,e,t.container)),void h("pvc-dashboard-widget-loaded",e)}window.postViewsChart.config=window.pvcUpdateConfig(window.postViewsChart.config,e),window.postViewsChart.config.options.plugins.legend.display=!i,window.postViewsChart.update(),i&&k("post-views",window.postViewsChart,e,t.container),h("pvc-dashboard-widget-loaded",e)},errorMessage:i.loadError}),w("post-most-viewed",{buildRequest:function(e){return{action:"pvc_dashboard_post_most_viewed",nonce:pvcArgs.nonce,period:e.period||"",datenav:e.datenav||"",lang:pvcArgs.lang?pvcArgs.lang:""}},render:function(e,t){f(t.container,e.dates),t.container.find("#pvc-post-most-viewed-content").html(e.html),h("pvc-dashboard-widget-loaded",e)},errorMessage:i.loadError}),window.pvcUpdatePostViewsWidget=function(){x("post-views",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))},window.pvcUpdatePostMostViewedWidget=function(){x("post-most-viewed",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))},window.pvcLoadPostViewsData=function(){x("post-views",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))},window.pvcLoadPostMostViewedData=function(){x("post-most-viewed",c(arguments.length>0&&void 0!==arguments[0]?arguments[0]:""))}}(jQuery); 3 3 4 4 })(jQuery, window, document); -
post-views-counter/tags/1.8.0/js/admin-post.js
r3443281 r3734102 1 1 ;(function($, window, document){ 2 var $;($=jQuery)(function(){var t=$("#post-views -input-container"),s=$("#post-views-display b"),e=$("#post-views-input"),i=$("#post-views .edit-post-views");i.on("click",function(s){return t.is(":hidden")&&(t.slideDown("fast"),$(s.currentTarget).hide()),!1}),$("#post-views .save-post-views").on("click",function(){var n=s.text().trim();return t.slideUp("fast"),i.show(),n=parseInt(e.val(),10),e.val(n),s.text(n),!1}),$("#post-views .cancel-post-views").on("click",function(){var n=s.text().trim();return t.slideUp("fast"),i.show(),n=parseInt($("#post-views-current").val(),10),s.text(n),e.val(n),!1})});2 var $;($=jQuery)(function(){var t=$("#post-views"),n=$("#post-views-input-container"),i=t.find(".edit-post-views"),e=document.documentElement.lang||void 0,r=[{$display:$("#post-views-display b"),$input:$("#post-views-input"),$current:$("#post-views-current")}],s=function(t){try{return new Intl.NumberFormat(e).format(t)}catch(n){return String(t)}};i.on("click",function(t){return n.is(":hidden")&&(n.slideDown("fast"),$(t.currentTarget).hide(),$("#post-views-input").trigger("focus")),!1}),t.find(".save-post-views").on("click",function(){return r.forEach(function(t){var n=t.$display,i=t.$input;if(i.length&&!i.prop("disabled")){var e=String(i.val()).trim();/^-?\d+$/.test(e)&&n.text(s(Math.max(0,parseInt(e,10))))}}),n.slideUp("fast"),i.show().trigger("focus"),!1}),t.find(".cancel-post-views").on("click",function(){return r.forEach(function(t){var n=t.$display,i=t.$input,e=t.$current;if(i.length&&e.length&&!i.prop("disabled")){var r=parseInt(e.val(),10);i.val(r),n.text(s(r))}}),n.slideUp("fast"),i.show().trigger("focus"),!1})}); 3 3 4 4 })(jQuery, window, document); -
post-views-counter/tags/1.8.0/js/admin-quick-edit.js
r3578455 r3734102 1 1 ;(function($, window, document){ 2 function t(n){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(n)}var $;($=jQuery)(function(){var n= window.pvcArgsQuickEdit||{nonce:"",wpVersion59:!1},i=["aa","mm","jj","hh","mn","ss"],e=function(t){if("string"!=typeof t)return"";var n=t.trim();if(""===n)return"";var i=n.replace(/[^0-9-]+/g,"");return""===i||/^-?$/.test(i)||!/^-?\d+$/.test(i)?"":i},r=function(t){if(!(t<=0)){var n=$("#edit-".concat(t));n.length&&n.find(':input[name="post_views"]').length&&i.forEach(function(i){var e=n.find(':input[name="'.concat(i,'"]')).first();if(e.length&&!/^\d+$/.test(String(e.val()||"").trim())){var r=function(t,n){return $("#inline_".concat(t)).find(".".concat(n)).first().text().trim()}(t,i);/^\d+$/.test(r)&&e.val(r)}})}},o=function(t){if(!(t<=0)){var n=$("#edit-".concat(t)),i=function(t){var n=$(".column-post_views",t),i=n.find("[data-post-views]").first(),r=e(i.attr("data-post-views")||"");return""!==r?r:e(n.text())}($("#post-".concat(t)));$(':input[name="post_views"]',n).val(i),$(':input[name="current_post_views"]',n).val(i)}},a=function(){var n=window.inlineEditPost;if(!n||"function"!=typeof n.edit)return!1;if(n._pvcPostViewsWrapped)return!0;var i=n.edit;return n.edit=function(n){var e=i.apply(this,arguments),r=function(n,i){return"object"===t(i)?parseInt(n.getId(i),10):parseInt(i,10)}(this,n);return o(r),e},n._pvcPostViewsWrapped=!0,!0},c=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;a()||t>=40||window.setTimeout(function(){c(t+1)},50)};c(),document.addEventListener("click",function(t){if(t.target&&t.target.closest){var n=t.target.closest("button.save");if(n){var i=$(n.closest('tr.inline-editor[id^="edit-"]'));i.length&&function(t){var n=e(String(t.find(':input[name="post_views"]').val()||"")),i=e(String(t.find(':input[name="current_post_views"]').val()||""));return""!==n&&n!==i}(i)&&r(parseInt(i.attr("id").replace("edit-",""),10))}}},!0),$(document).off("click.pvcBulkEdit","#bulk_edit").on("click.pvcBulkEdit","#bulk_edit",function(){var t=$("#bulk-edit"),i=[];n.wpVersion59?t.find("#bulk-titles-list").children(".ntdelitem").each(function(){var t=$(this).find("button").attr("id")||"";i.push(t.replace(/[^0-9]/g,""))}):t.find("#bulk-titles").children().each(function(){var t=$(this).attr("id")||"";i.push(t.replace(/^(ttle)/i,""))});var e=t.find('input[name="post_views"]').val();$.ajax({url:ajaxurl,type:"post",async:!1,cache:!1,data:{action:"save_bulk_post_views",post_ids:i.filter(Boolean),post_views:e,current_post_views:e,nonce:n.nonce}})})});2 function t(n){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(n)}var $;($=jQuery)(function(){var n=["aa","mm","jj","hh","mn","ss"],e=function(t){if("string"!=typeof t)return"";var n=t.trim();if(""===n)return"";var e=n.replace(/[^0-9-]+/g,"");return""===e||/^-?$/.test(e)||!/^-?\d+$/.test(e)?"":e},i=function(t){if(!(t<=0)){var e=$("#edit-".concat(t));e.length&&e.find(':input[name="post_views"]').length&&n.forEach(function(n){var i=e.find(':input[name="'.concat(n,'"]')).first();if(i.length&&!/^\d+$/.test(String(i.val()||"").trim())){var r=function(t,n){return $("#inline_".concat(t)).find(".".concat(n)).first().text().trim()}(t,n);/^\d+$/.test(r)&&i.val(r)}})}},r=function(t){if(!(t<=0)){var n=$("#edit-".concat(t)),i=$(':input[name="post_views"]',n);if(i.length){var r=$(':input[name="current_post_views"]',n);if("1"!==i.attr("data-pvc-editable"))return i.prop("disabled",!0).prop("readonly",!0).val(""),void r.val("");var o,a=(o=$("#post-".concat(t)),e($(".column-post_views",o).find("[data-post-views]").first().attr("data-post-views")||""));i.prop("disabled",!1).prop("readonly",!1).val(a),r.val(a)}}},o=function(){var n=window.inlineEditPost;if(!n||"function"!=typeof n.edit)return!1;if(n._pvcPostViewsWrapped)return!0;var e=n.edit;return n.edit=function(n){var i=e.apply(this,arguments),o=function(n,e){return"object"===t(e)?parseInt(n.getId(e),10):parseInt(e,10)}(this,n);return r(o),i},n._pvcPostViewsWrapped=!0,!0},a=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;o()||t>=40||window.setTimeout(function(){a(t+1)},50)};a(),document.addEventListener("click",function(t){if(t.target&&t.target.closest){var n=t.target.closest("button.save");if(n){var r=$(n.closest('tr.inline-editor[id^="edit-"]'));r.length&&function(t){var n=e(String(t.find(':input[name="post_views"]').val()||"")),i=e(String(t.find(':input[name="current_post_views"]').val()||""));return""!==n&&n!==i}(r)&&i(parseInt(r.attr("id").replace("edit-",""),10))}}},!0)}); 3 3 4 4 })(jQuery, window, document); -
post-views-counter/tags/1.8.0/js/admin-settings.js
r3578455 r3734102 1 1 ;(function($, window, document){ 2 const e=(e,t=0,n=1)=>e>n?n:e<t?t:e,t=(e,t=0,n=Math.pow(10,t))=>Math.round(n*e)/n,n=e=>("#"===e[0]&&(e=e.substring(1)),e.length<6?{r:parseInt(e[0]+e[0],16),g:parseInt(e[1]+e[1],16),b:parseInt(e[2]+e[2],16),a:4===e.length?t(parseInt(e[3]+e[3],16)/255,2):1}:{r:parseInt(e.substring(0,2),16),g:parseInt(e.substring(2,4),16),b:parseInt(e.substring(4,6),16),a:8===e.length?t(parseInt(e.substring(6,8),16)/255,2):1}),r=e=>{const{h:n,s:r,l:o}=(({h:e,s:n,v:r,a:o})=>{const i=(200-n)*r/100;return{h:t(e),s:t(i>0&&i<200?n*r/100/(i<=100?i:200-i)*100:0),l:t(i/2),a:t(o,2)}})(e);return`hsl(${n}, ${r}%, ${o}%)`},o=({h:e,s:n,v:r,a:o})=>{e=e/360*6,n/=100,r/=100;const i=Math.floor(e),a=r*(1-n),s=r*(1-(e-i)*n),c=r*(1-(1-e+i)*n), u=i%6;return{r:t(255*[r,s,a,a,c,r][u]),g:t(255*[c,r,r,s,a,a][u]),b:t(255*[a,a,c,r,r,s][u]),a:t(o,2)}},i=e=>{const t=e.toString(16);return t.length<2?"0"+t:t},a=({r:e,g:n,b:r,a:o})=>{const a=o<1?i(t(255*o)):"";return"#"+i(e)+i(n)+i(r)+a},s=({r:e,g:n,b:r,a:o})=>{const i=Math.max(e,n,r),a=i-Math.min(e,n,r),s=a?i===e?(n-r)/a:i===n?2+(r-e)/a:4+(e-n)/a:0;return{h:t(60*(s<0?s+6:s)),s:t(i?a/i*100:0),v:t(i/255*100),a:o}},c=(e,t)=>{if(e===t)return!0;for(const n in e)if(e[n]!==t[n])return!1;return!0},u={},l=e=>{let t=u[e];return t||(t=document.createElement("template"),t.innerHTML=e,u[e]=t),t},d=(e,t,n)=>{e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:n}))};let f=!1;const v=e=>"touches"in e,p=(t,n)=>{const r=v(n)?n.touches[0]:n,o=t.el.getBoundingClientRect();d(t.el,"move",t.getMove({x:e((r.pageX-(o.left+window.pageXOffset))/o.width),y:e((r.pageY-(o.top+window.pageYOffset))/o.height)}))};class h{constructor(e,t,n,r){const o=l(`<div role="slider" tabindex="0" part="${t}" ${n}><div part="${t}-pointer"></div></div>`);e.appendChild(o.content.cloneNode(!0));const i=e.querySelector(`[part=${t}]`);i.addEventListener("mousedown",this),i.addEventListener("touchstart",this),i.addEventListener("keydown",this),this.el=i,this.xy=r,this.nodes=[i.firstChild,i]}set dragging(e){const t=e?document.addEventListener:document.removeEventListener;t(f?"touchmove":"mousemove",this),t(f?"touchend":"mouseup",this)}handleEvent(e){switch(e.type){case"mousedown":case"touchstart":if(e.preventDefault(),!(e=>!(f&&!v(e)||(f||(f=v(e)),0)))(e)||!f&&0!=e.button)return;this.el.focus(),p(this,e),this.dragging=!0;break;case"mousemove":case"touchmove":e.preventDefault(),p(this,e);break;case"mouseup":case"touchend":this.dragging=!1;break;case"keydown":((e,t)=>{const n=t.keyCode;n>40||e.xy&&n<37||n<33||(t.preventDefault(),d(e.el,"move",e.getMove({x:39===n?.01:37===n?-.01:34===n?.05:33===n?-.05:35===n?1:36===n?-1:0,y:40===n?.01:38===n?-.01:0},!0)))})(this,e)}}style(e){e.forEach((e,t)=>{for(const n in e)this.nodes[t].style.setProperty(n,e[n])})}}class m extends h{constructor(e){super(e,"hue",'aria-label="Hue" aria-valuemin="0" aria-valuemax="360"',!1)}update({h:e}){this.h=e,this.style([{left:e/360*100+"%",color:r({h:e,s:100,v:100,a:1})}]),this.el.setAttribute("aria-valuenow",`${t(e)}`)}getMove(t,n){return{h:n?e(this.h+360*t.x,0,360):360*t.x}}}class g extends h{constructor(e){super(e,"saturation",'aria-label="Color"',!0)}update(e){this.hsva=e,this.style([{top:100-e.v+"%",left:`${e.s}%`,color:r(e)},{"background-color":r({h:e.h,s:100,v:100,a:1})}]),this.el.setAttribute("aria-valuetext",`Saturation ${t(e.s)}%, Brightness ${t(e.v)}%`)}getMove(t,n){return{s:n?e(this.hsva.s+100*t.x,0,100):100*t.x,v:n?e(this.hsva.v-100*t.y,0,100):Math.round(100-100*t.y)}}}const b=Symbol("same"),y=Symbol("color"),x=Symbol("hsva"),w=Symbol("update"),E=Symbol("parts"),L=Symbol("css"),A=Symbol("sliders");class S extends HTMLElement{static get observedAttributes(){return["color"]}get[L](){return[':host{display:flex;flex-direction:column;position:relative;width:200px;height:200px;user-select:none;-webkit-user-select:none;cursor:default}:host([hidden]){display:none!important}[role=slider]{position:relative;touch-action:none;user-select:none;-webkit-user-select:none;outline:0}[role=slider]:last-child{border-radius:0 0 8px 8px}[part$=pointer]{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;display:flex;place-content:center center;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}[part$=pointer]::after{content:"";width:100%;height:100%;border-radius:inherit;background-color:currentColor}[role=slider]:focus [part$=pointer]{transform:translate(-50%,-50%) scale(1.1)}',"[part=hue]{flex:0 0 24px;background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}[part=hue-pointer]{top:50%;z-index:2}","[part=saturation]{flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,rgba(255,255,255,0));box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}[part=saturation-pointer]{z-index:3}"]}get[A](){return[g,m]}get color(){return this[y]}set color(e){if(!this[b](e)){const t=this.colorModel.toHsva(e);this[w](t),this[y]=e}}constructor(){super();const e=l(`<style>${this[L].join("")}</style>`),t=this.attachShadow({mode:"open"});t.appendChild(e.content.cloneNode(!0)),t.addEventListener("move",this),this[E]=this[A].map(e=>new e(t))}connectedCallback(){if(this.hasOwnProperty("color")){const e=this.color;delete this.color,this.color=e}else this.color||(this.color=this.colorModel.defaultColor)}attributeChangedCallback(e,t,n){const r=this.colorModel.fromAttr(n);this[b](r)||(this.color=r)}handleEvent(e){const t=this[x],n={...t,...e.detail};let r;this[w](n),c(n,t)||this[b](r=this.colorModel.fromHsva(n))||(this[y]=r,d(this,"color-changed",{value:r}))}[b](e){return this.color&&this.colorModel.equal(e,this.color)}[w](e){this[x]=e,this[E].forEach(t=>t.update(e))}}const k={defaultColor:"#000",toHsva:e=>s(n(e)),fromHsva:({h:e,s:t,v:n})=>a(o({h:e,s:t,v:n,a:1})),equal:(e,t)=>e.toLowerCase()===t.toLowerCase()||c(n(e),n(t)),fromAttr:e=>e};class _ extends S{get colorModel(){return k}}function q(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return C(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?C(e,t):void 0}}(e))||t){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,s=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){s=!0,i=e},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw i}}}}function C(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function M(e){return M="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},M(e)}customElements.define("hex-color-picker",class extends _{});var $,I=/^[0-9a-f]{3}([0-9a-f]{3})?$/i,P=function(e){if(!e)return"";var t=e.trim();if(!t)return"";var n=t.startsWith("#")?t.slice(1):t;return I.test(n)?"#".concat(n.toLowerCase()):""};function O(){var e=document.querySelector("[data-settings-prefix]"),t=e?e.dataset.settingsPrefix:"";if(t){var n=".".concat(t,"-hex-color-picker"),r=".".concat(t,"-field-type-color"),o=".".concat(t,"-color-input"),i=".".concat(t,"-color-swatch"),a=".".concat(t,"-color-popover"),s=".".concat(t,"-color-control"),c="".concat(t,"ColorInitialized");document.querySelectorAll(r).forEach(function(e){if("true"!==e.dataset[c]){var t=e.querySelector(o),r=e.querySelector(i),u=e.querySelector(a),l=e.querySelector(n),d=e.querySelector(s);if(t&&r&&u&&l&&d){l.addEventListener("mousedown",function(e){return e.stopPropagation()}),e.dataset[c]="true";var f=P(t.value)||"#000000",v=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=n.setInput,i=void 0===o||o,a=n.dispatch,s=void 0===a||a,c=n.setPicker,u=void 0===c||c,d=P(e);return!!d&&(f=d,i&&(t.value=d),r.style.backgroundColor=d,u&&l.color!==d&&(l.color=d),s&&t.dispatchEvent(new Event("input",{bubbles:!0})),!0)},p=function(){e.classList.contains("is-open")||(e.classList.add("is-open"),u.removeAttribute("aria-hidden"),r.setAttribute("aria-expanded","true"),document.addEventListener("mousedown",m,!0),document.addEventListener("keydown",g))},h=function(){e.classList.contains("is-open")&&(e.classList.remove("is-open"),u.setAttribute("aria-hidden","true"),r.setAttribute("aria-expanded","false"),document.removeEventListener("mousedown",m,!0),document.removeEventListener("keydown",g))},m=function(e){var t="function"==typeof e.composedPath?e.composedPath():[];d.contains(e.target)||t.includes(d)||t.includes(u)||t.includes(l)||h()},g=function(e){"Escape"===e.key&&h()};v(f,{setInput:!0,dispatch:!1}),r.addEventListener("click",function(t){t.preventDefault(),e.classList.contains("is-open")?h():p()}),t.addEventListener("click",p),t.addEventListener("input",function(){var e=P(t.value);e&&(t.value!==e&&(t.value=e),f=e,r.style.backgroundColor=e,l.color!==e&&(l.color=e))}),t.addEventListener("blur",function(){v(t.value,{setInput:!0,dispatch:!1})||v(f,{setInput:!0,dispatch:!1})}),l.addEventListener("color-changed",function(e){v(e.detail.value,{setPicker:!1})})}}})}}function T(){document.querySelectorAll('input[type="range"][data-range-output]').forEach(function(e){var t=e.getAttribute("data-range-output"),n=document.getElementById(t);n&&e.addEventListener("input",function(){n.textContent=e.value})})}function H(){var e=document.querySelector("[data-settings-prefix]"),t=e?e.dataset.settingsPrefix:"";if(t){var n="data-".concat(t,"-logic"),r="data-".concat(t,"-fallback-option"),o="".concat(t,"-hidden"),i="".concat(t,"CondDisabled"),a="_".concat(t,"AnimHandler"),s=[],c=new Map;document.querySelectorAll("[".concat(n,"]")).forEach(function(e){var o,i,a=function(e){var t=e.getAttribute(n);if(!t)return[];try{var r=JSON.parse(t);if(Array.isArray(r))return r;if(r&&"object"===M(r))return[r]}catch(o){return[]}return[]}(e);if(a.length){var u=a.map(function(e){return{field:e.field,operator:e.operator,value:e.value,scope:e.scope||"field",action:e.action||"",target:e.target||"",container:e.container||""}}),l=(null===(o=u.find(function(e){return e.container}))||void 0===o?void 0:o.container)||"",d=null;"self"===l?d=e:l&&(d=e.querySelector(l)||document.querySelector(l)),d||(d=e.closest("tr")||e);var f=e.getAttribute("data-".concat(t,"-animation")),v=(null===(i=u.find(function(e){return e.action}))||void 0===i?void 0:i.action)||"show",p=e.getAttribute(r)||"",h={el:e,row:d,logic:u,animation:f,defaultAction:v,fallbackOption:p};s.push(h),u.forEach(function(e){c.has(e.field)||c.set(e.field,[]);var t=c.get(e.field);t.includes(h)||t.push(h)})}});var u=function(e){var t=function(e){var t=document.getElementById(e);if(t)return"checkbox"===t.type||"radio"===t.type?t.checked?t.value:"":t.value;var n=document.querySelectorAll('input[type="radio"][id^="'.concat(e,'-"]'));if(n.length>0){var r,o=q(n);try{for(o.s();!(r=o.n()).done;){var i=r.value;if(i.checked)return i.value}}catch(c){o.e(c)}finally{o.f()}return null}var a=document.querySelectorAll('input[type="checkbox"][id^="'.concat(e,'-"]'));if(a.length>0){var s=[];return a.forEach(function(e){e.checked&&s.push(e.value)}),s}return null}(e.field);if(null===t)return!1;switch(e.operator){case"is":return t===e.value;case"isnot":return t!==e.value;case"contains":return("string"==typeof t||Array.isArray(t))&&t.includes(e.value);case"containsnot":return("string"==typeof t||Array.isArray(t))&&!t.includes(e.value);default:return!1}},l=function(e,n){var r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],i=e.row,s=e.animation,c=i.classList.contains(o);if(n===!c)return Promise.resolve();if(!r||!s||!["fade","slide"].includes(s))return i.classList.toggle(o,!n),Promise.resolve();var u="".concat(t,"-anim-in"),l="".concat(t,"-anim-out"),d="".concat(t,"-anim-").concat(s);return new Promise(function(e){i[a]&&(i.removeEventListener("animationend",i[a]),i[a]=null);var t=function(){i.classList.remove(u,l,d),n?i.classList.remove(o):i.classList.add(o),i.removeEventListener("animationend",t),i[a]=null,e()};i.classList.remove(u,l,d),n?(i.classList.remove(o),i.classList.add(u,d)):i.classList.add(l,d),i[a]=t,i.addEventListener("animationend",t,{once:!0})})},d=function(e,t){e.el.querySelectorAll("input, select, textarea, button").forEach(function(e){t?e.disabled||(e.dataset[i]="true",e.disabled=!0):"true"===e.dataset[i]&&(e.disabled=!1,delete e.dataset[i])})},f=function(e,t,n,r){var a=e.action||r;if(a){var s=function(e,t){if(e.target)return Array.from(document.querySelectorAll(e.target));var n=t.el.querySelectorAll('input[type="radio"]');if(n.length)return Array.from(n).filter(function(t){return t.value===e.value});var r=t.el.querySelectorAll('input[type="checkbox"]');if(r.length)return Array.from(r).filter(function(t){return t.value===e.value});var o=t.el.querySelector("select");return o?Array.from(o.options).filter(function(t){return t.value===e.value}):[]}(e,t);s.length&&s.forEach(function(e){if("disable"===a||"enable"===a)!function(e,t){t?e.disabled||(e.dataset[i]="true",e.disabled=!0):"true"===e.dataset[i]&&(e.disabled=!1,delete e.dataset[i])}(e,"disable"===a?n:!n);else if("show"===a||"hide"===a){var t="show"===a?n:!n;e.classList.toggle(o,!t)}})}},v=function(e){if(e.fallbackOption){var t=e.el.querySelectorAll('input[type="radio"]');if(t.length){var n=Array.from(t).find(function(e){return e.checked});if(!n||n.disabled){var r=Array.from(t).find(function(t){return t.value===e.fallbackOption&&!t.disabled});r||(r=Array.from(t).find(function(e){return!e.disabled})||null),r&&!r.checked&&(r.checked=!0,r.dispatchEvent(new Event("change",{bubbles:!0})))}}else{var o=e.el.querySelector("select");if(o){var i=o.options[o.selectedIndex];if(i&&!i.disabled)return;var a=Array.from(o.options).find(function(t){return t.value===e.fallbackOption&&!t.disabled});a||(a=Array.from(o.options).find(function(e){return!e.disabled})),a&&(o.value=a.value,o.dispatchEvent(new Event("change",{bubbles:!0})))}}}},p=new Set,h=new Map;c.forEach(function(e,t){if(!p.has(t)){h.has(t)||h.set(t,{seq:0});!function(e,t){var n=document.getElementById(e);if(n)return n.addEventListener("change",t),void n.addEventListener("input",t);document.querySelectorAll('input[type="radio"][id^="'.concat(e,'-"]')).forEach(function(e){e.addEventListener("change",t)}),document.querySelectorAll('input[type="checkbox"][id^="'.concat(e,'-"]')).forEach(function(e){e.addEventListener("change",t)})}(t,function(){var n=h.get(t),r=++n.seq,i=[],a=[];if(e.forEach(function(e){var t,n=e.logic.filter(function(e){return"option"===e.scope}),r=e.logic.filter(function(e){return"option"!==e.scope});if(n.forEach(function(t){var n=u(t);f(t,e,n,e.defaultAction)}),v(e),r.length){var s=(null===(t=r.find(function(e){return e.action}))||void 0===t?void 0:t.action)||e.defaultAction,c=r.every(function(e){return u(e)});if("enable"!==s&&"disable"!==s){var l=e.row.classList.contains(o),p="show"===s?c:!c;p&&l?a.push(e):p||l||i.push(e)}else{d(e,"disable"===s?c:!c)}}}),i.length>0){var s=i.map(function(e){return l(e,!1,!0)});Promise.all(s).then(function(){n.seq===r&&a.forEach(function(e){return l(e,!0,!0)})})}else a.forEach(function(e){return l(e,!0,!0)})}),p.add(t)}}),s.forEach(function(e){var t,n=e.logic.filter(function(e){return"option"===e.scope}),r=e.logic.filter(function(e){return"option"!==e.scope});if(n.forEach(function(t){var n=u(t);f(t,e,n,e.defaultAction)}),v(e),r.length){var o=(null===(t=r.find(function(e){return e.action}))||void 0===t?void 0:t.action)||e.defaultAction,i=r.every(function(e){return u(e)});if("enable"!==o&&"disable"!==o)l(e,"show"===o?i:!i,!1);else d(e,"disable"===o?i:!i)}})}}function j(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"slide",r=document.querySelector("[data-settings-prefix]"),o=r?r.dataset.settingsPrefix:"";if(!o)return e.style.display=t?"":"none",Promise.resolve();var i="".concat(o,"-hidden"),a="".concat(o,"-anim-in"),s="".concat(o,"-anim-out"),c="".concat(o,"-anim-").concat(n),u="_".concat(o,"AnimHandler");return new Promise(function(n){e[u]&&(e.removeEventListener("animationend",e[u]),e[u]=null);var r=function(){e.classList.remove(a,s,c),t?e.classList.remove(i):e.classList.add(i),e.removeEventListener("animationend",r),e[u]=null,n()};e.classList.remove(a,s,c),t?(e.classList.remove(i),e.classList.add(a,c)):e.classList.add(s,c),e[u]=r,e.addEventListener("animationend",r,{once:!0})})}function D(e){return"sent"===e?"success":"not_enough_data"===e?"warning":"error"}function N(e,t){var n,r,o=document.getElementById("pvc-email-test-notice"),i="notice notice-error inline";o&&(t?("success"===e?i="notice notice-success inline":"warning"===e&&(i="notice notice-warning inline"),o.innerHTML='<div class="'.concat(i,'"><p>').concat((n=t,(r=document.createElement("div")).textContent=null==n?"":String(n),r.innerHTML),"</p></div>")):o.innerHTML="")}document.addEventListener("DOMContentLoaded",function(){O(),T(),H()}),document.addEventListener("wpAjaxContentLoaded",function(){O(),T(),H()}),($=jQuery)(function(){var e=$("#pvc-general-exclude-ips-setting"),t=window.pvcArgsSettings||{},n=t.testEmail||{},r=e.find(".pvc-ip-box").length,o=function(){e.find(".pvc-remove-exclude-ip").each(function(e,t){0===e?t.classList.add("pvc-hidden"):r>1?t.classList.remove("pvc-hidden"):t.classList.add("pvc-hidden")})};o(),$(document).on("click",".reset_pvc_settings",function(){var e=confirm(t.resetToDefaults);return e&&$(this).hasClass("reset_post_views_counter_settings_other")&&$('input[data-pvc-menu="submenu"]').after($('input[data-pvc-menu="topmenu"]')),e}),$(document).on("click",'input[name="post_views_counter_reset_views"]',function(){return confirm(t.resetViews)}),$(document).on("click",'input[name="post_views_counter_import_views"]',function(){return confirm(t.importViews)}),$(document).on("click",".pvc-remove-exclude-ip",function(e){e.preventDefault();var t=$(this).closest(".pvc-ip-box")[0];j(t,!1).then(function(){return t.remove(),r--,o(),null}).catch(function(){return null})});var i=/^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/,a=function(e){if(!e)return!1;var t=e.trim();return function(e){var t=-1!==e.indexOf("*")?e.replace(/\*/g,"0"):e;return i.test(t)}(t)||function(e){if(-1===e.indexOf(":")||-1!==e.indexOf("*"))return!1;try{return""!==new URL("http://[".concat(e,"]")).hostname}catch(t){return!1}}(t)};$(document).on("click",".pvc-add-exclude-ip",function(){var e=$(this).parents("#pvc-general-exclude-ips-setting"),t=e.find('.pvc-ip-box:last input[type="text"]'),n=t.val().trim();if(a(n)){r++;var i=e.find(".pvc-ip-box:last").clone();i.find("input").val(""),i[0].classList.add("pvc-hidden"),e.find(".pvc-ip-box:last").after(i),j(i[0],!0),o()}else t.focus()}),$(document).on("click",".pvc-add-current-ip",function(){$(this).parents("#pvc-general-exclude-ips-setting").find(".pvc-ip-box").last().find("input").val($(this).attr("data-rel"))}),$('input[name="post_views_counter_settings_display[menu_position]"], input[name="post_views_counter_settings_other[menu_position]"]').on("change",function(){"top"===$(this).val()?$('input[data-pvc-menu="submenu"]').after($('input[data-pvc-menu="topmenu"]')):$('input[data-pvc-menu="submenu"]').before($('input[data-pvc-menu="topmenu"]'))}),$(document).on("click",".pvc-send-test-email",function(e){e.preventDefault();var t=e.currentTarget,r=t.closest(".pvc-email-test-scaffold"),o=r?r.querySelector("#pvc-test-email-recipient"):null,i=t.dataset.pvcEmailTestNonce||"",a=t.dataset.defaultLabel||t.textContent.trim(),s=t.dataset.sendingLabel||a,c=n.unexpectedError||"The test email request could not be completed. Please try again.",u=n.invalidResponse||"The test email request did not return a valid response.";o&&"string"==typeof ajaxurl&&""!==ajaxurl?(t.disabled=!0,t.textContent=s,N("success",""),$.ajax({url:ajaxurl,method:"POST",dataType:"json",data:{action:"pvc_send_test_email",nonce:i,pvc_test_email_recipient:o.value}}).done(function(e){e&&void 0!==e.success&&e.data&&e.data.message?N(D(e.success?"sent":e.data.code),e.data.message):N("error",u)}).fail(function(e){var t=e.responseJSON&&e.responseJSON.data?e.responseJSON.data:null,n=t&&t.code?t.code:"",r=t&&t.message?t.message:c;N(D(n),r)}).always(function(){t.disabled=!1,t.textContent=a})):N("error",c)})});2 const e=(e,t=0,n=1)=>e>n?n:e<t?t:e,t=(e,t=0,n=Math.pow(10,t))=>Math.round(n*e)/n,n=e=>("#"===e[0]&&(e=e.substring(1)),e.length<6?{r:parseInt(e[0]+e[0],16),g:parseInt(e[1]+e[1],16),b:parseInt(e[2]+e[2],16),a:4===e.length?t(parseInt(e[3]+e[3],16)/255,2):1}:{r:parseInt(e.substring(0,2),16),g:parseInt(e.substring(2,4),16),b:parseInt(e.substring(4,6),16),a:8===e.length?t(parseInt(e.substring(6,8),16)/255,2):1}),r=e=>{const{h:n,s:r,l:o}=(({h:e,s:n,v:r,a:o})=>{const i=(200-n)*r/100;return{h:t(e),s:t(i>0&&i<200?n*r/100/(i<=100?i:200-i)*100:0),l:t(i/2),a:t(o,2)}})(e);return`hsl(${n}, ${r}%, ${o}%)`},o=({h:e,s:n,v:r,a:o})=>{e=e/360*6,n/=100,r/=100;const i=Math.floor(e),a=r*(1-n),s=r*(1-(e-i)*n),c=r*(1-(1-e+i)*n),l=i%6;return{r:t(255*[r,s,a,a,c,r][l]),g:t(255*[c,r,r,s,a,a][l]),b:t(255*[a,a,c,r,r,s][l]),a:t(o,2)}},i=e=>{const t=e.toString(16);return t.length<2?"0"+t:t},a=({r:e,g:n,b:r,a:o})=>{const a=o<1?i(t(255*o)):"";return"#"+i(e)+i(n)+i(r)+a},s=({r:e,g:n,b:r,a:o})=>{const i=Math.max(e,n,r),a=i-Math.min(e,n,r),s=a?i===e?(n-r)/a:i===n?2+(r-e)/a:4+(e-n)/a:0;return{h:t(60*(s<0?s+6:s)),s:t(i?a/i*100:0),v:t(i/255*100),a:o}},c=(e,t)=>{if(e===t)return!0;for(const n in e)if(e[n]!==t[n])return!1;return!0},l={},u=e=>{let t=l[e];return t||(t=document.createElement("template"),t.innerHTML=e,l[e]=t),t},d=(e,t,n)=>{e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:n}))};let f=!1;const v=e=>"touches"in e,p=(t,n)=>{const r=v(n)?n.touches[0]:n,o=t.el.getBoundingClientRect();d(t.el,"move",t.getMove({x:e((r.pageX-(o.left+window.pageXOffset))/o.width),y:e((r.pageY-(o.top+window.pageYOffset))/o.height)}))};class h{constructor(e,t,n,r){const o=u(`<div role="slider" tabindex="0" part="${t}" ${n}><div part="${t}-pointer"></div></div>`);e.appendChild(o.content.cloneNode(!0));const i=e.querySelector(`[part=${t}]`);i.addEventListener("mousedown",this),i.addEventListener("touchstart",this),i.addEventListener("keydown",this),this.el=i,this.xy=r,this.nodes=[i.firstChild,i]}set dragging(e){const t=e?document.addEventListener:document.removeEventListener;t(f?"touchmove":"mousemove",this),t(f?"touchend":"mouseup",this)}handleEvent(e){switch(e.type){case"mousedown":case"touchstart":if(e.preventDefault(),!(e=>!(f&&!v(e)||(f||(f=v(e)),0)))(e)||!f&&0!=e.button)return;this.el.focus(),p(this,e),this.dragging=!0;break;case"mousemove":case"touchmove":e.preventDefault(),p(this,e);break;case"mouseup":case"touchend":this.dragging=!1;break;case"keydown":((e,t)=>{const n=t.keyCode;n>40||e.xy&&n<37||n<33||(t.preventDefault(),d(e.el,"move",e.getMove({x:39===n?.01:37===n?-.01:34===n?.05:33===n?-.05:35===n?1:36===n?-1:0,y:40===n?.01:38===n?-.01:0},!0)))})(this,e)}}style(e){e.forEach((e,t)=>{for(const n in e)this.nodes[t].style.setProperty(n,e[n])})}}class m extends h{constructor(e){super(e,"hue",'aria-label="Hue" aria-valuemin="0" aria-valuemax="360"',!1)}update({h:e}){this.h=e,this.style([{left:e/360*100+"%",color:r({h:e,s:100,v:100,a:1})}]),this.el.setAttribute("aria-valuenow",`${t(e)}`)}getMove(t,n){return{h:n?e(this.h+360*t.x,0,360):360*t.x}}}class g extends h{constructor(e){super(e,"saturation",'aria-label="Color"',!0)}update(e){this.hsva=e,this.style([{top:100-e.v+"%",left:`${e.s}%`,color:r(e)},{"background-color":r({h:e.h,s:100,v:100,a:1})}]),this.el.setAttribute("aria-valuetext",`Saturation ${t(e.s)}%, Brightness ${t(e.v)}%`)}getMove(t,n){return{s:n?e(this.hsva.s+100*t.x,0,100):100*t.x,v:n?e(this.hsva.v-100*t.y,0,100):Math.round(100-100*t.y)}}}const b=Symbol("same"),y=Symbol("color"),x=Symbol("hsva"),w=Symbol("update"),E=Symbol("parts"),L=Symbol("css"),A=Symbol("sliders");class S extends HTMLElement{static get observedAttributes(){return["color"]}get[L](){return[':host{display:flex;flex-direction:column;position:relative;width:200px;height:200px;user-select:none;-webkit-user-select:none;cursor:default}:host([hidden]){display:none!important}[role=slider]{position:relative;touch-action:none;user-select:none;-webkit-user-select:none;outline:0}[role=slider]:last-child{border-radius:0 0 8px 8px}[part$=pointer]{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;display:flex;place-content:center center;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}[part$=pointer]::after{content:"";width:100%;height:100%;border-radius:inherit;background-color:currentColor}[role=slider]:focus [part$=pointer]{transform:translate(-50%,-50%) scale(1.1)}',"[part=hue]{flex:0 0 24px;background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}[part=hue-pointer]{top:50%;z-index:2}","[part=saturation]{flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,rgba(255,255,255,0));box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}[part=saturation-pointer]{z-index:3}"]}get[A](){return[g,m]}get color(){return this[y]}set color(e){if(!this[b](e)){const t=this.colorModel.toHsva(e);this[w](t),this[y]=e}}constructor(){super();const e=u(`<style>${this[L].join("")}</style>`),t=this.attachShadow({mode:"open"});t.appendChild(e.content.cloneNode(!0)),t.addEventListener("move",this),this[E]=this[A].map(e=>new e(t))}connectedCallback(){if(this.hasOwnProperty("color")){const e=this.color;delete this.color,this.color=e}else this.color||(this.color=this.colorModel.defaultColor)}attributeChangedCallback(e,t,n){const r=this.colorModel.fromAttr(n);this[b](r)||(this.color=r)}handleEvent(e){const t=this[x],n={...t,...e.detail};let r;this[w](n),c(n,t)||this[b](r=this.colorModel.fromHsva(n))||(this[y]=r,d(this,"color-changed",{value:r}))}[b](e){return this.color&&this.colorModel.equal(e,this.color)}[w](e){this[x]=e,this[E].forEach(t=>t.update(e))}}const k={defaultColor:"#000",toHsva:e=>s(n(e)),fromHsva:({h:e,s:t,v:n})=>a(o({h:e,s:t,v:n,a:1})),equal:(e,t)=>e.toLowerCase()===t.toLowerCase()||c(n(e),n(t)),fromAttr:e=>e};class _ extends S{get colorModel(){return k}}function q(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(e){if("string"==typeof e)return C(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?C(e,t):void 0}}(e))||t){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,s=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){s=!0,i=e},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw i}}}}function C(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function M(e){return M="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},M(e)}customElements.define("hex-color-picker",class extends _{});var $,I=/^[0-9a-f]{3}([0-9a-f]{3})?$/i,O=function(e){if(!e)return"";var t=e.trim();if(!t)return"";var n=t.startsWith("#")?t.slice(1):t;return I.test(n)?"#".concat(n.toLowerCase()):""};function P(){var e=document.querySelector("[data-settings-prefix]"),t=e?e.dataset.settingsPrefix:"";if(t){var n=".".concat(t,"-hex-color-picker"),r=".".concat(t,"-field-type-color"),o=".".concat(t,"-color-input"),i=".".concat(t,"-color-swatch"),a=".".concat(t,"-color-popover"),s=".".concat(t,"-color-control"),c="".concat(t,"ColorInitialized");document.querySelectorAll(r).forEach(function(e){if("true"!==e.dataset[c]){var t=e.querySelector(o),r=e.querySelector(i),l=e.querySelector(a),u=e.querySelector(n),d=e.querySelector(s);if(t&&r&&l&&u&&d){u.addEventListener("mousedown",function(e){return e.stopPropagation()}),e.dataset[c]="true";var f=O(t.value)||"#000000",v=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=n.setInput,i=void 0===o||o,a=n.dispatch,s=void 0===a||a,c=n.setPicker,l=void 0===c||c,d=O(e);return!!d&&(f=d,i&&(t.value=d),r.style.backgroundColor=d,l&&u.color!==d&&(u.color=d),s&&t.dispatchEvent(new Event("input",{bubbles:!0})),!0)},p=function(){e.classList.contains("is-open")||(e.classList.add("is-open"),l.removeAttribute("aria-hidden"),r.setAttribute("aria-expanded","true"),document.addEventListener("mousedown",m,!0),document.addEventListener("keydown",g))},h=function(){e.classList.contains("is-open")&&(e.classList.remove("is-open"),l.setAttribute("aria-hidden","true"),r.setAttribute("aria-expanded","false"),document.removeEventListener("mousedown",m,!0),document.removeEventListener("keydown",g))},m=function(e){var t="function"==typeof e.composedPath?e.composedPath():[];d.contains(e.target)||t.includes(d)||t.includes(l)||t.includes(u)||h()},g=function(e){"Escape"===e.key&&h()};v(f,{setInput:!0,dispatch:!1}),r.addEventListener("click",function(t){t.preventDefault(),e.classList.contains("is-open")?h():p()}),t.addEventListener("click",p),t.addEventListener("input",function(){var e=O(t.value);e&&(t.value!==e&&(t.value=e),f=e,r.style.backgroundColor=e,u.color!==e&&(u.color=e))}),t.addEventListener("blur",function(){v(t.value,{setInput:!0,dispatch:!1})||v(f,{setInput:!0,dispatch:!1})}),u.addEventListener("color-changed",function(e){v(e.detail.value,{setPicker:!1})})}}})}}function T(){document.querySelectorAll('input[type="range"][data-range-output]').forEach(function(e){var t=e.getAttribute("data-range-output"),n=document.getElementById(t);n&&e.addEventListener("input",function(){n.textContent=e.value})})}function H(){var e=document.querySelector("[data-settings-prefix]"),t=e?e.dataset.settingsPrefix:"";if(t){var n=!1,r="data-".concat(t,"-logic"),o="data-".concat(t,"-fallback-option"),i="".concat(t,"-hidden"),a="".concat(t,"CondDisabled"),s="_".concat(t,"AnimHandler"),c=[],l=new Map;document.querySelectorAll("[".concat(r,"]")).forEach(function(e){var n,i,a=function(e){var t=e.getAttribute(r);if(!t)return[];try{var n=JSON.parse(t);if(Array.isArray(n))return n;if(n&&"object"===M(n))return[n]}catch(o){return[]}return[]}(e);if(a.length){var s=a.map(function(e){return{field:e.field,operator:e.operator,value:e.value,scope:e.scope||"field",action:e.action||"",target:e.target||"",container:e.container||"",clearOnDisable:!0===e.clear_on_disable}}),u=(null===(n=s.find(function(e){return e.container}))||void 0===n?void 0:n.container)||"",d=null;"self"===u?d=e:u&&(d=e.querySelector(u)||document.querySelector(u)),d||(d=e.closest("tr")||e);var f=e.getAttribute("data-".concat(t,"-animation")),v=(null===(i=s.find(function(e){return e.action}))||void 0===i?void 0:i.action)||"show",p=e.getAttribute(o)||"",h={el:e,row:d,logic:s,animation:f,defaultAction:v,fallbackOption:p};c.push(h),s.forEach(function(e){l.has(e.field)||l.set(e.field,[]);var t=l.get(e.field);t.includes(h)||t.push(h)})}});var u=function(e){var t=function(e){var t=document.getElementById(e);if(t)return"checkbox"===t.type||"radio"===t.type?t.checked?t.value:"":t.value;var n=document.querySelectorAll('input[type="radio"][id^="'.concat(e,'-"]'));if(n.length>0){var r,o=q(n);try{for(o.s();!(r=o.n()).done;){var i=r.value;if(i.checked)return i.value}}catch(c){o.e(c)}finally{o.f()}return null}var a=document.querySelectorAll('input[type="checkbox"][id^="'.concat(e,'-"]'));if(a.length>0){var s=[];return a.forEach(function(e){e.checked&&s.push(e.value)}),s}return null}(e.field);if(null===t)return!1;switch(e.operator){case"is":return t===e.value;case"isnot":return t!==e.value;case"contains":return("string"==typeof t||Array.isArray(t))&&t.includes(e.value);case"containsnot":return("string"==typeof t||Array.isArray(t))&&!t.includes(e.value);default:return!1}},d=function(e,r){var o=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],a=e.row,c=e.animation,l=a.classList.contains(i);if(r===!l)return Promise.resolve();if(n||!o||!c||!["fade","slide"].includes(c))return a.classList.toggle(i,!r),Promise.resolve();var u="".concat(t,"-anim-in"),d="".concat(t,"-anim-out"),f="".concat(t,"-anim-").concat(c);return new Promise(function(e){a[s]&&(a.removeEventListener("animationend",a[s]),a[s]=null);var t=function(){a.classList.remove(u,d,f),r?a.classList.remove(i):a.classList.add(i),a.removeEventListener("animationend",t),a[s]=null,e()};a.classList.remove(u,d,f),r?(a.classList.remove(i),a.classList.add(u,f)):a.classList.add(d,f),a[s]=t,a.addEventListener("animationend",t,{once:!0})})},f=function(e,t){e.el.querySelectorAll("input, select, textarea, button").forEach(function(e){t?e.disabled||(e.dataset[a]="true",e.disabled=!0):"true"===e.dataset[a]&&(e.disabled=!1,delete e.dataset[a])})},v=function(e,t,n,r){var o=e.action||r;if(o){var s=function(e,t){if(e.target)return Array.from(document.querySelectorAll(e.target));var n=t.el.querySelectorAll('input[type="radio"]');if(n.length)return Array.from(n).filter(function(t){return t.value===e.value});var r=t.el.querySelectorAll('input[type="checkbox"]');if(r.length)return Array.from(r).filter(function(t){return t.value===e.value});var o=t.el.querySelector("select");return o?Array.from(o.options).filter(function(t){return t.value===e.value}):[]}(e,t);s.length&&s.forEach(function(t){if("disable"===o||"enable"===o)!function(e,t){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(t){if(!e.disabled){var r=!!n&&function(e){return!("checkbox"!==e.type&&"radio"!==e.type||!e.checked||(e.checked=!1,0))}(e);e.dataset[a]="true",e.disabled=!0,r&&e.dispatchEvent(new Event("change",{bubbles:!0}))}}else"true"===e.dataset[a]&&(e.disabled=!1,delete e.dataset[a])}(t,"disable"===o?n:!n,e.clearOnDisable);else if("show"===o||"hide"===o){var r="show"===o?n:!n;t.classList.toggle(i,!r)}})}},p=function(e){if(e.fallbackOption){var t=e.el.querySelectorAll('input[type="radio"]');if(t.length){var n=Array.from(t).find(function(e){return e.checked});if(!n||n.disabled){var r=Array.from(t).find(function(t){return t.value===e.fallbackOption&&!t.disabled});r||(r=Array.from(t).find(function(e){return!e.disabled})||null),r&&!r.checked&&(r.checked=!0,r.dispatchEvent(new Event("change",{bubbles:!0})))}}else{var o=e.el.querySelector("select");if(o){var i=o.options[o.selectedIndex];if(i&&!i.disabled)return;var a=Array.from(o.options).find(function(t){return t.value===e.fallbackOption&&!t.disabled});a||(a=Array.from(o.options).find(function(e){return!e.disabled})),a&&(o.value=a.value,o.dispatchEvent(new Event("change",{bubbles:!0})))}}}},h=new Set,m=new Map;l.forEach(function(e,t){if(!h.has(t)){m.has(t)||m.set(t,{seq:0});!function(e,t){var n=document.getElementById(e);if(n)return n.addEventListener("change",t),void n.addEventListener("input",t);document.querySelectorAll('input[type="radio"][id^="'.concat(e,'-"]')).forEach(function(e){e.addEventListener("change",t)}),document.querySelectorAll('input[type="checkbox"][id^="'.concat(e,'-"]')).forEach(function(e){e.addEventListener("change",t)})}(t,function(){var n=m.get(t);if(!n.running){n.running=!0;try{!function(t){var n=++t.seq,r=[],o=[];if(e.forEach(function(e){var t,n=e.logic.filter(function(e){return"option"===e.scope}),a=e.logic.filter(function(e){return"option"!==e.scope});if(n.forEach(function(t){var n=u(t);v(t,e,n,e.defaultAction)}),p(e),a.length){var s=(null===(t=a.find(function(e){return e.action}))||void 0===t?void 0:t.action)||e.defaultAction,c=a.every(function(e){return u(e)});if("enable"!==s&&"disable"!==s){var l=e.row.classList.contains(i),d="show"===s?c:!c;d&&l?o.push(e):d||l||r.push(e)}else f(e,"disable"===s?c:!c)}}),r.length>0){var a=r.map(function(e){return d(e,!1,!0)});Promise.all(a).then(function(){t.seq===n&&o.forEach(function(e){return d(e,!0,!0)})})}else o.forEach(function(e){return d(e,!0,!0)})}(n)}finally{n.running=!1}}}),h.add(t)}}),n=!0,c.forEach(function(e){var t,n=e.logic.filter(function(e){return"option"===e.scope}),r=e.logic.filter(function(e){return"option"!==e.scope});if(n.forEach(function(t){var n=u(t);v(t,e,n,e.defaultAction)}),p(e),r.length){var o=(null===(t=r.find(function(e){return e.action}))||void 0===t?void 0:t.action)||e.defaultAction,i=r.every(function(e){return u(e)});if("enable"!==o&&"disable"!==o)d(e,"show"===o?i:!i,!1);else f(e,"disable"===o?i:!i)}}),n=!1}}function j(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"slide",r=document.querySelector("[data-settings-prefix]"),o=r?r.dataset.settingsPrefix:"";if(!o)return e.style.display=t?"":"none",Promise.resolve();var i="".concat(o,"-hidden"),a="".concat(o,"-anim-in"),s="".concat(o,"-anim-out"),c="".concat(o,"-anim-").concat(n),l="_".concat(o,"AnimHandler");return new Promise(function(n){e[l]&&(e.removeEventListener("animationend",e[l]),e[l]=null);var r=function(){e.classList.remove(a,s,c),t?e.classList.remove(i):e.classList.add(i),e.removeEventListener("animationend",r),e[l]=null,n()};e.classList.remove(a,s,c),t?(e.classList.remove(i),e.classList.add(a,c)):e.classList.add(s,c),e[l]=r,e.addEventListener("animationend",r,{once:!0})})}function D(e){return"sent"===e?"success":"not_enough_data"===e?"warning":"error"}function N(e,t){var n,r,o=document.getElementById("pvc-email-test-notice"),i="notice notice-error inline";o&&(t?("success"===e?i="notice notice-success inline":"warning"===e&&(i="notice notice-warning inline"),o.innerHTML='<div class="'.concat(i,'"><p>').concat((n=t,(r=document.createElement("div")).textContent=null==n?"":String(n),r.innerHTML),"</p></div>")):o.innerHTML="")}document.addEventListener("DOMContentLoaded",function(){P(),T(),H()}),document.addEventListener("wpAjaxContentLoaded",function(){P(),T(),H()}),($=jQuery)(function(){var e=$("#pvc-general-exclude-ips-setting"),t=window.pvcArgsSettings||{},n=t.testEmail||{},r=e.find(".pvc-ip-box").length,o=function(){e.find(".pvc-remove-exclude-ip").each(function(e,t){0===e?t.classList.add("pvc-hidden"):r>1?t.classList.remove("pvc-hidden"):t.classList.add("pvc-hidden")})};o(),$(document).on("click",".reset_pvc_settings",function(){var e=confirm(t.resetToDefaults);return e&&$(this).hasClass("reset_post_views_counter_settings_other")&&$('input[data-pvc-menu="submenu"]').after($('input[data-pvc-menu="topmenu"]')),e}),$(document).on("click",'input[name="post_views_counter_reset_views"]',function(){return confirm(t.resetViews)}),$(document).on("click",'input[name="post_views_counter_import_views"]',function(){return confirm(t.importViews)}),$(document).on("click",".pvc-remove-exclude-ip",function(e){e.preventDefault();var t=$(this).closest(".pvc-ip-box")[0];j(t,!1).then(function(){return t.remove(),r--,o(),null}).catch(function(){return null})});var i=/^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/,a=function(e){if(!e)return!1;var t=e.trim();return function(e){var t=-1!==e.indexOf("*")?e.replace(/\*/g,"0"):e;return i.test(t)}(t)||function(e){if(-1===e.indexOf(":")||-1!==e.indexOf("*"))return!1;try{return""!==new URL("http://[".concat(e,"]")).hostname}catch(t){return!1}}(t)};$(document).on("click",".pvc-add-exclude-ip",function(){var e=$(this).parents("#pvc-general-exclude-ips-setting"),t=e.find('.pvc-ip-box:last input[type="text"]'),n=t.val().trim();if(a(n)){r++;var i=e.find(".pvc-ip-box:last").clone();i.find("input").val(""),i[0].classList.add("pvc-hidden"),e.find(".pvc-ip-box:last").after(i),j(i[0],!0),o()}else t.focus()}),$(document).on("click",".pvc-add-current-ip",function(){$(this).parents("#pvc-general-exclude-ips-setting").find(".pvc-ip-box").last().find("input").val($(this).attr("data-rel"))}),$('input[name="post_views_counter_settings_display[menu_position]"], input[name="post_views_counter_settings_other[menu_position]"]').on("change",function(){"top"===$(this).val()?$('input[data-pvc-menu="submenu"]').after($('input[data-pvc-menu="topmenu"]')):$('input[data-pvc-menu="submenu"]').before($('input[data-pvc-menu="topmenu"]'))}),$(document).on("click",".pvc-send-test-email",function(e){e.preventDefault();var t=e.currentTarget,r=t.closest(".pvc-email-test-scaffold"),o=r?r.querySelector("#pvc-test-email-recipient"):null,i=t.dataset.pvcEmailTestNonce||"",a=t.dataset.defaultLabel||t.textContent.trim(),s=t.dataset.sendingLabel||a,c=n.unexpectedError||"The test email request could not be completed. Please try again.",l=n.invalidResponse||"The test email request did not return a valid response.";o&&"string"==typeof ajaxurl&&""!==ajaxurl?(t.disabled=!0,t.textContent=s,N("success",""),$.ajax({url:ajaxurl,method:"POST",dataType:"json",data:{action:"pvc_send_test_email",nonce:i,pvc_test_email_recipient:o.value}}).done(function(e){e&&void 0!==e.success&&e.data&&e.data.message?N(D(e.success?"sent":e.data.code),e.data.message):N("error",l)}).fail(function(e){var t=e.responseJSON&&e.responseJSON.data?e.responseJSON.data:null,n=t&&t.code?t.code:"",r=t&&t.message?t.message:c;N(D(n),r)}).always(function(){t.disabled=!1,t.textContent=a})):N("error",c)})}); 3 3 4 4 })(jQuery, window, document); -
post-views-counter/tags/1.8.0/js/block-editor.js
r3647380 r3734102 1 1 (function(){ 2 function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t( e,t){for(var i=0;i<t.length;i++){var o=t[i];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,n(o.key),o)}}function n(t){var n=function(t,n){if("object"!=e(t)||!t)return t;var i=t[Symbol.toPrimitive];if(void 0!==i){var o=i.call(t,n);if("object"!=e(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t,"string");return"symbol"==e(n)?n:n+""}function i(t,n,i){return n=s(n),function(t,n){if(n&&("object"==e(n)||"function"==typeof n))return n;if(void 0!==n)throw new TypeError("Derived constructors may only return object or undefined");return function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(t)}(t,o()?Reflect.construct(n,i||[],s(t).constructor):n.apply(t,i))}function o(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(o=function(){return!!e})()}function s(e){return s=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)},s(e)}function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}var l=wp.element,a=l.Fragment,c=l.Component,p=wp.data.withSelect,u=wp.plugins.registerPlugin,d=wp.components,w=d.TextControl,m=d.Button,v=d.Popover,f=wp.editor.PluginPostStatusInfo,h=function(){function e(){var t;return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),(t=i(this,e,arguments)).state={postViews:pvcEditorArgs.postViews,isVisible:!1},t.handleClick=t.handleClick.bind(t),t.handleClickOutside=t.handleClickOutside.bind(t),t.handleCancel=t.handleCancel.bind(t),t.handleSetViews=t.handleSetViews.bind(t),t}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,"prototype",{writable:!1}),t&&r(e,t)}(e,c),n=e,o=[{key:"handleClick",value:function(e){e.target.classList.contains("edit-post-post-views-toggle-link")&&this.setState(function(e){return{isVisible:!e.isVisible}})}},{key:"handleClickOutside",value:function(e){e.target.classList.contains("edit-post-post-views-toggle-link")||this.setState(function(e){return{isVisible:!e.isVisible}})}},{key:"handleCancel",value:function(e){this.setState(function(e){return{postViews:pvcEditorArgs.postViews,isVisible:!e.isVisible}})}},{key:"handleSetViews",value:function(e){wp.data.dispatch("core/editor").editPost({meta:{_pvc_post_views:e}}),this.setState(function(){return{postViews:e}})}},{key:"render",value:function(){return wp.element.createElement(b,{postViews:this.state.postViews,isVisible:this.state.isVisible,handleClick:this.handleClick,handleClickOutside:this.handleClickOutside,handleCancel:this.handleCancel,handleSetViews:this.handleSetViews})}}],s=[{key:"getDerivedStateFromProps",value:function(e,t){!e.isPublishing&&!e.isSaving||e.isAutoSaving||wp.apiRequest({path:"/post-views-counter/update-post-views/?id=".concat(e.postId),method:"POST",data:{post_views:t.postViews}}).then(function(e){return e},function(e){return e})}}],o&&t(n.prototype,o),s&&t(n,s),Object.defineProperty(n,"prototype",{writable:!1}),n;var n,o,s}(),b=function(e){return wp.element.createElement(a,null,wp.element.createElement(f,{className:"edit-post-post-views"},wp.element.createElement("div",{className:"editor-post-panel__row-label"},wp.element.createElement("span",null,pvcEditorArgs.textPostViews)),!pvcEditorArgs.canEdit&&wp.element.createElement("div",{className:"editor-post-panel__row-control"},wp.element.createElement("div",{className:"components-dropdown edit-post-post-views-popover-wrapper"},wp.element.createElement(m,{size:"compact",variant:"tertiary",disabled:!0,className:"components-button edit-post-post-views-toggle-link"},e.postViews))),pvcEditorArgs.canEdit&&wp.element.createElement("div",{className:"editor-post-panel__row-control"},wp.element.createElement("div",{className:"components-dropdown edit-post-post-views-popover-wrapper"},wp.element.createElement(m,{size:"compact",variant:"tertiary",className:"components-button edit-post-post-views-toggle-link",onClick:e.handleClick},e.postViews,e.isVisible&&(pvcEditorArgs.wpGreater53?wp.element.createElement(v,{position:"bottom right",className:"edit-post-post-views-popover",onFocusOutside:e.handleClickOutside},wp.element.createElement("legend",null,pvcEditorArgs.textPostViews),wp.element.createElement(w,{className:"edit-post-post-views-input",type:"number",key:"post_views",value:e.postViews,onChange:e.handleSetViews}),wp.element.createElement("p",{className:"description"},pvcEditorArgs.textHelp),wp.element.createElement(m,{variant:"link",className:"edit-post-post-views-cancel-link",onClick:e.handleCancel},pvcEditorArgs.textCancel)):wp.element.createElement(v,{position:"bottom right",className:"edit-post-post-views-popover",onClickOutside:e.handleClickOutside},wp.element.createElement("legend",null,pvcEditorArgs.textPostViews),wp.element.createElement(w,{className:"edit-post-post-views-input",type:"number",key:"post_views",value:e.postViews,onChange:e.handleSetViews}),wp.element.createElement("p",{className:"description"},pvcEditorArgs.textHelp),wp.element.createElement(m,{variant:"link",className:"edit-post-post-views-cancel-link",onClick:e.handleCancel},pvcEditorArgs.textCancel))))))))};u("post-views-counter",{icon:"",render:p(function(e,t){var n=t.forceIsSaving,i=e("core/editor"),o=i.getCurrentPostId,s=i.isSavingPost,r=i.isPublishingPost,l=i.isAutosavingPost;return{postId:o(),isSaving:n||s(),isAutoSaving:l(),isPublishing:r()}})(h)});2 function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t(t,n,r){return(n=function(t){var n=function(t,n){if("object"!=e(t)||!t)return t;var r;if("undefined"!=typeof Symbol&&void 0!==(r=t[Symbol.toPrimitive])){var o=r.call(t,n);if("object"!=e(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===n?String:Number)(t)}(t,"string");return"symbol"==e(n)?n:n+""}(n))in t?Object.defineProperty(t,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[n]=r,t}var n=["views"],r=function(e){return null==e?"":String(e)},o=function(e){return r(e).trim()},i=function(e,t){try{return new Intl.NumberFormat(t||void 0).format(e)}catch(n){return(new Intl.NumberFormat).format(e)}};function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}function s(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i,a,s=[],u=!0,c=!1;try{if(i=(n=n.call(e)).next,0===t);else for(;!(u=(r=i.call(n)).done)&&(s.push(r.value),s.length!==t);u=!0);}catch(e){c=!0,o=e}finally{try{if(!u&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(c)throw o}}return s}}(e,t)||function(e,t){if(e){if("string"==typeof e)return u(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?u(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function c(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=a(e)||!e)return e;var n;if("undefined"!=typeof Symbol&&void 0!==(n=e[Symbol.toPrimitive])){var r=n.call(e,t);if("object"!=a(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==a(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var l,p,v,f,m,d,b,w,y,g,S,h,E,P,N,j,O,A,C=wp.element,I=C.useState,_=C.useEffect,T=wp.plugins.registerPlugin,k=wp.components,D=k.TextControl,x=k.Button,F=k.Dropdown,q=wp.editor&&wp.editor.PluginPostStatusInfo||wp.editPost&&wp.editPost.PluginPostStatusInfo,M=window.pvcEditorArgs,B=M.i18n,V="pvc-counter-totals",z="pvc_counter_totals",H=(l={views:M.views,canEdit:M.canEdit,request:function(e){return wp.apiFetch({path:"/post-views-counter/update-post-views/?id=".concat(M.postID),method:"POST",data:e}).then(function(e){return wp.data.dispatch("core/notices").removeNotice(V),e})},onError:function(e){var t=e&&e.message?" ".concat(e.message):"";wp.data.dispatch("core/notices").createErrorNotice(B.saveFailed+t,{id:V,isDismissible:!0})},onPending:function(e){var t=wp.data.select("core/editor"),n=Object.prototype.hasOwnProperty.call(t.getPostEdits(),z);e&&!n?wp.data.dispatch("core/editor").editPost(c({},z,Date.now())):!e&&n&&wp.data.dispatch("core/editor").editPost(c({},z,void 0))}},p=l.views,v=l.canEdit,f=l.request,m=l.onError,d=l.onPending,b={baseline:{views:Number(p)||0},values:{views:r(p)},saving:!1},w=!1,y=new Set,S=function(e){if(!g(e))return!1;var t=o(b.values[e]);return""!==t&&t!==r(b.baseline[e])},E=function(e){b=Object.assign({},b,e),y.forEach(function(e){return e(b)}),d&&!b.saving&&d(h())},P=function(){return n.reduce(function(e,t){return S(t)&&(e[t]=o(b.values[t])),e},{})},N=function(){if(b.saving)return w=!0,Promise.resolve(!1);var e=P();return Object.keys(e).length?(E({saving:!0}),Promise.resolve().then(function(){return f(e)}).then(function(t){var i={views:Number(t.views)||0},a=Object.assign({},b.values);return n.forEach(function(t){var n=o(b.values[t]);(Object.prototype.hasOwnProperty.call(e,t)?n===e[t]:!S(t))&&(a[t]=r(i[t]))}),E({baseline:i,values:a,saving:!1}),!0},function(e){return E({saving:!1}),m&&m(e),!1}).then(function(e){return w?(w=!1,N()):e})):Promise.resolve(!1)},{getState:function(){return b},subscribe:function(e){return y.add(e),function(){return y.delete(e)}},isEditable:g=function(e){return!!v&&n.includes(e)},isDirty:S,hasPendingEdits:h=function(){return n.some(S)},getPayload:P,setValue:function(e,n){g(e)&&E({values:Object.assign({},b.values,t({},e,r(n)))})},reset:function(e){E({values:Object.assign({},b.values,t({},e,r(b.baseline[e])))})},submit:N});if(M.canEdit){var L=(j=function(){return H.submit()},O=!1,A=!1,function(e){var t=e.isSaving,n=e.isAutosaving,r=e.didSucceed;if(t)return O||(A=!1),O=!0,void(A=A||!!n);O&&(O=!1,!A&&r&&j())});wp.data.subscribe(function(){var e=wp.data.select("core/editor");L({isSaving:e.isSavingPost(),isAutosaving:e.isAutosavingPost(),didSucceed:e.didPostSaveRequestSucceed()})})}var R=function(e){var t,n=e.metric,r=e.label,a=function(){var e=s(I(H.getState()),2),t=e[0],n=e[1];return _(function(){var e=H.subscribe(n);return function(){e()}},[]),t}(),u=function(e,t){var n=o(e.values[t]);return/^\d+$/.test(n)?i(Number(n),M.locale):""===n?i(e.baseline[t],M.locale):n}(a,n);return t=H.isEditable(n)?wp.element.createElement(F,{className:"edit-post-post-views-popover-wrapper",contentClassName:"edit-post-post-views-popover",popoverProps:{placement:"bottom-end"},renderToggle:function(e){var t=e.isOpen,n=e.onToggle;return wp.element.createElement(x,{size:"compact",variant:"tertiary",className:"edit-post-post-views-toggle-link","aria-expanded":t,"aria-label":B.valueLabel.replace("%1$s",r).replace("%2$s",u),onClick:n},u)},renderContent:function(e){var t=e.onClose;return wp.element.createElement("div",{className:"edit-post-post-views-popover-content"},wp.element.createElement(D,{__nextHasNoMarginBottom:!0,label:r,className:"edit-post-post-views-input",type:"number",min:0,step:1,inputMode:"numeric",value:a.values[n],onChange:function(e){return H.setValue(n,e)}}),wp.element.createElement("p",{className:"description"},B.help),wp.element.createElement(x,{variant:"link",className:"edit-post-post-views-cancel-link",onClick:function(){H.reset(n),t()}},B.cancel))}}):wp.element.createElement("span",{className:"edit-post-post-views-value"},u),wp.element.createElement(q,{className:"edit-post-post-views edit-post-post-".concat(n)},wp.element.createElement("div",{className:"editor-post-panel__row-label"},wp.element.createElement("span",null,r)),wp.element.createElement("div",{className:"editor-post-panel__row-control"},t))};T("post-views-counter",{icon:"",render:function(){return wp.element.createElement(R,{metric:"views",label:B.views})}}); 3 3 4 4 })(); -
post-views-counter/tags/1.8.0/js/frontend.js
r3578455 r3734102 1 function t(t){return function(t){if(Array.isArray(t))return e(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,o){if(t){if("string"==typeof t)return e(t,o);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?e(t,o):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var o=0,n=Array(e);o<e;o++)n[o]=t[o];return n}function o(t){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},o(t)}window.PostViewsCounter={promise:null,args:{},init:function(t){ this.args=t;var e={storage_type:"cookies",storage_data:this.readCookieData("pvc_visits".concat(!1!==t.multisite?"_".concat(parseInt(t.multisite,10)):""))};"rest_api"===t.mode?this.promise=this.request(t.requestURL,e,"POST",{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8","X-WP-Nonce":t.nonce}):(e.action="pvc-check-post",e.pvc_nonce=t.nonce,e.id=t.postID,this.promise=this.request(t.requestURL,e,"POST",{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"}))},request:function(t,e,n,r){var a=this,c={method:n,mode:"cors",cache:"no-cache",credentials:"same-origin",headers:r,body:this.prepareRequestData(e)};return fetch(t,c).then(function(t){if(!t.ok)throw Error(t.statusText);return t.json()}).then(function(t){try{"object"===o(t)&&null!==t?"success"in t&&!1===t.success?(console.log("PVC: Request error."),console.log(t.data)):(a.saveCookieData(t.storage),a.triggerEvent("pvcCheckPost",t)):(console.log("PVC: Invalid object."),console.log(t))}catch(e){console.log("PVC: Invalid JSON data."),console.log(e)}}).catch(function(t){console.log("PVC: Invalid response."),console.log(t)})},prepareRequestData:function(t){return Object.keys(t).map(function(e){return"".concat(encodeURIComponent(e),"=").concat(encodeURIComponent(t[e]))}).join("&").replace(/%20/g,"+")},triggerEvent:function(t,e){var o=new CustomEvent(t,{bubbles:!0,detail:e});document.dispatchEvent(o)},getCookiePath:function(){var t="string"==typeof this.args.path?this.args.path.trim():"";if(!t||"/"===t)return"/";var e=t.replace(/\/{2,}/g,"/").replace(/^\/+|\/+$/g,"");return e?"/".concat(e,"/"):"/"},saveCookieData:function(e){var o=this;if(e&&Object.prototype.hasOwnProperty.call(e,"name")){var n=t(new Set(e.name.map(function(t){return t.replace(/\[\d+\]$/,"")}))),r="";"https:"===document.location.protocol&&(r=";secure"),n.forEach(function(t){document.cookie.split(";").forEach(function(e){if(e&&e.trim()){var n=e.split("=")[0];if(n){var a=n.trim();new RegExp("^".concat(t,"\\[(\\d+)\\]$")).test(a)&&(document.cookie="".concat(a,"=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=").concat(o.getCookiePath(),";domain=").concat(o.args.domain).concat(r,";SameSite=Lax"))}}})});for(var a=0;a<e.name.length;a++){var c=new Date,i=parseInt(e.expiry[a],10),s=e.value[a];"string"!=typeof s&&(s=String(null!=s?s:"")),i?i*=1e3:i=c.getTime()+864e5,c.setTime(i),document.cookie="".concat(e.name[a],"=").concat(encodeURIComponent(s),";expires=").concat(c.toUTCString(),";path=").concat(this.getCookiePath(),";domain=").concat(this.args.domain).concat(r,";SameSite=Lax")}}},readCookieData:function(t){var e=[];document.cookie.split(";").forEach(function(o){if(o&&o.trim()){var n=o.split("="),r=n[0],a=n.slice(1).join("=");if(r){var c=r.trim(),i=new RegExp("^".concat(t,"\\[(\\d+)\\]$")),s=c.match(i);if(s){var u=a||"";try{u=decodeURIComponent(u)}catch(l){u=a||""}e.push({index:parseInt(s[1],10),value:u})}}}}),e.sort(function(t,e){return t.index-e.index});var n=e.map(function(t){return t.value}),r=n.join("");if(r)try{var a=JSON.parse(r);if(a&&"object"===o(a)&&1===a.version)return r}catch(c){}return n.join("a")}};var n=function(){return window.PostViewsCounter.init(pvcArgsFrontend)};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",n):n();1 function t(t){return function(t){if(Array.isArray(t))return e(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,o){if(t){if("string"==typeof t)return e(t,o);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?e(t,o):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var o=0,n=Array(e);o<e;o++)n[o]=t[o];return n}function o(t){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},o(t)}window.PostViewsCounter={promise:null,args:{},init:function(t){if(this.args=t,this.loadDynamicMetrics(),!0===t.countEnabled){var e={storage_type:"cookies",storage_data:this.readCookieData("pvc_visits".concat(!1!==t.multisite?"_".concat(parseInt(t.multisite,10)):"")),storage_capable:this.isCookieStorageAvailable()?1:0};"rest_api"===t.mode?this.promise=this.request(t.requestURL,e,"POST",{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8","X-WP-Nonce":t.nonce}):(e.action="pvc-check-post",e.pvc_nonce=t.nonce,e.id=t.postID,this.promise=this.request(t.requestURL,e,"POST",{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"}))}},loadDynamicMetrics:function(){var t=this;if("string"==typeof this.args.displayURL&&""!==this.args.displayURL){var e=new Map;new Set(document.querySelectorAll(".post-views.load-dynamic, [data-pvc-metric].load-dynamic")).forEach(function(t){var o=t.getAttribute("data-pvc-metric"),n=t.getAttribute("data-pvc-type"),r=t.getAttribute("data-pvc-id"),a=t.getAttribute("data-pvc-period"),i=null===o?"views":o,c=null===a?"total":a,s=n,u=r;if(null===n&&null===r){var l=t.className.match(/(?:^|\s)post-([1-9]\d*)(?=\s|$)/);s=null===l?null:"post",u=null===l?null:l[1]}if("post"!==s||null===u||!/^[1-9]\d*$/.test(u)||"views"!==i||!/^[a-z0-9_-]+$/.test(c))return t.classList.add("loaded","load-error"),t.classList.remove("loading"),void t.removeAttribute("aria-busy");var d=parseInt(u,10),p="".concat(i,":").concat(s,":").concat(d,":").concat(c);e.has(p)||e.set(p,{metric:i,id:d,type:s,period:c,elements:[]}),e.get(p).elements.push(t),t.classList.add("loading"),t.classList.remove("loaded","load-error"),t.setAttribute("aria-busy","true")}),e.forEach(function(e){var n=e.metric,r=e.id,a=e.type,i=e.period,c=e.elements,s="total"!==i||c.some(function(t){return"true"===t.getAttribute("data-pvc-server-formatted")}),u=s?"?metric=".concat(encodeURIComponent(n),"&type=").concat(encodeURIComponent(a),"&period=").concat(encodeURIComponent(i)):"";fetch("".concat(t.args.displayURL,"/").concat(r).concat(u),{method:"GET",credentials:"same-origin",cache:"no-cache"}).then(function(t){if(!t.ok)throw new Error(t.statusText);return t.json()}).then(function(t){var e=t,n=t;if(s){var u="".concat(a,":").concat(r,":").concat(i);if(!t||"object"!==o(t)||!t.values||!Object.prototype.hasOwnProperty.call(t.values,u))throw new Error("Invalid display response");e=t.values[u],n=t.formatted&&Object.prototype.hasOwnProperty.call(t.formatted,u)?t.formatted[u]:e}if(!(("number"==typeof e||"string"==typeof e)&&""!==e&&Number.isFinite(Number(e))))throw new Error("Invalid metric value");if(s&&!["string","number"].includes(o(n)))throw new Error("Invalid formatted metric value");c.forEach(function(t){var o=t.querySelector(".post-views-count");o&&(o.textContent=String(s?n:e)),t.classList.add("loaded"),t.classList.remove("loading","load-error"),t.removeAttribute("aria-busy")})}).catch(function(){c.forEach(function(t){t.classList.add("loaded","load-error"),t.classList.remove("loading"),t.removeAttribute("aria-busy")})})})}},request:function(t,e,n,r){var a=this,i={method:n,mode:"cors",cache:"no-cache",credentials:"same-origin",headers:r,body:this.prepareRequestData(e)};return fetch(t,i).then(function(t){if(!t.ok)throw Error(t.statusText);return t.json()}).then(function(t){try{"object"===o(t)&&null!==t?"success"in t&&!1===t.success?(console.log("PVC: Request error."),console.log(t.data)):(a.saveCookieData(t.storage),a.triggerEvent("pvcCheckPost",t)):(console.log("PVC: Invalid object."),console.log(t))}catch(e){console.log("PVC: Invalid JSON data."),console.log(e)}}).catch(function(t){console.log("PVC: Invalid response."),console.log(t)})},prepareRequestData:function(t){return Object.keys(t).map(function(e){return"".concat(encodeURIComponent(e),"=").concat(encodeURIComponent(t[e]))}).join("&").replace(/%20/g,"+")},triggerEvent:function(t,e){var o=new CustomEvent(t,{bubbles:!0,detail:e});document.dispatchEvent(o)},getCookiePath:function(){var t="string"==typeof this.args.path?this.args.path.trim():"";if(!t||"/"===t)return"/";var e=t.replace(/\/{2,}/g,"/").replace(/^\/+|\/+$/g,"");return e?"/".concat(e,"/"):"/"},saveCookieData:function(e){var n=this;if(e&&Object.prototype.hasOwnProperty.call(e,"name")&&!(!Array.isArray(e.name)||!Array.isArray(e.value)||e.name.length>4||e.name.some(function(t){return!/\[[0-3]\]$/.test(String(t))})||new Blob(e.value.map(function(t){return String(null!=t?t:"")})).size>15920)){var r=e.value.map(function(t){return String(null!=t?t:"")}).join("");if(r.trim().startsWith("{"))try{var a=JSON.parse(r);if(a&&"object"===o(a)&&Object.prototype.hasOwnProperty.call(a,"version")&&!this.isBoundedSessionPayload(a))return}catch(p){return}var i=t(new Set(e.name.map(function(t){return t.replace(/\[\d+\]$/,"")}))),c="";"https:"===document.location.protocol&&(c=";secure"),i.forEach(function(t){document.cookie.split(";").forEach(function(e){if(e&&e.trim()){var o=e.split("=")[0];if(o){var r=o.trim();new RegExp("^".concat(t,"\\[(\\d+)\\]$")).test(r)&&(document.cookie="".concat(r,"=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=").concat(n.getCookiePath(),";domain=").concat(n.args.domain).concat(c,";SameSite=Lax"))}}})});for(var s=0;s<e.name.length;s++){var u=new Date,l=parseInt(e.expiry[s],10),d=e.value[s];"string"!=typeof d&&(d=String(null!=d?d:"")),l?l*=1e3:l=u.getTime()+864e5,u.setTime(l),document.cookie="".concat(e.name[s],"=").concat(encodeURIComponent(d),";expires=").concat(u.toUTCString(),";path=").concat(this.getCookiePath(),";domain=").concat(this.args.domain).concat(c,";SameSite=Lax")}}},readCookieData:function(t){var e=[],n=!1;if(document.cookie.split(";").forEach(function(o){if(o&&o.trim()){var r=o.split("="),a=r[0],i=r.slice(1).join("=");if(a){var c=a.trim(),s=new RegExp("^".concat(t,"\\[(\\d+)\\]$")),u=c.match(s);if(u){if(parseInt(u[1],10)>=4)return void(n=!0);var l=i||"";try{l=decodeURIComponent(l)}catch(d){l=i||""}e.push({index:parseInt(u[1],10),value:l})}}}}),e.sort(function(t,e){return t.index-e.index}),n||e.some(function(t,e){return t.index!==e}))return"__pvc_invalid_storage_payload__";var r=e.map(function(t){return t.value});if(new Blob(r).size>15920)return"__pvc_invalid_storage_payload__";var a=r.join("");if(a)try{var i=JSON.parse(a);if(this.isBoundedSessionPayload(i))return a;if(i&&"object"===o(i)&&1===i.version)return"__pvc_invalid_storage_payload__"}catch(s){}var c=r.join("a");return c&&c.split("a").length>1e3?"__pvc_invalid_storage_payload__":c},isBoundedSessionPayload:function(t){if(!t||"object"!==o(t)||1!==t.version||!t.visited||"object"!==o(t.visited)||Array.isArray(t.visited))return!1;var e=Object.values(t.visited);return!(e.length>8||!e.every(Array.isArray))&&e.reduce(function(t,e){return t+new Set(e.map(function(t){return String(t)})).size},0)<=1e3},isCookieStorageAvailable:function(){var t="__pvcStorageTest_".concat(Date.now()),e="";"https:"===document.location.protocol&&(e=";secure");try{document.cookie="".concat(t,"=1;path=").concat(this.getCookiePath(),";domain=").concat(this.args.domain).concat(e,";SameSite=Lax");var o=document.cookie.split(";").some(function(e){return e.trim().startsWith("".concat(t,"="))});return document.cookie="".concat(t,"=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=").concat(this.getCookiePath(),";domain=").concat(this.args.domain).concat(e,";SameSite=Lax"),o}catch(n){return!1}}};var n=function(){return window.PostViewsCounter.init(pvcArgsFrontend)};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",n):n(); -
post-views-counter/tags/1.8.0/languages/post-views-counter.pot
r3647380 r3734102 1 #, fuzzy 1 # Copyright (C) 2026 dFactory 2 # This file is distributed under the MIT License. 2 3 msgid "" 3 4 msgstr "" 4 "Project-Id-Version: Post Views Counter\n" 5 "POT-Creation-Date: 2026-07-29 11:20+0200\n" 6 "PO-Revision-Date: 2015-04-08 18:59+0100\n" 7 "Last-Translator: Bartosz Arendt <info@dfactory.eu>\n" 8 "Language-Team: dFactory <info@dfactory.eu>\n" 9 "Language: en\n" 5 "Project-Id-Version: Post Views Counter 1.8.0\n" 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/post-views-counter\n" 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 8 "Language-Team: LANGUAGE <LL@li.org>\n" 10 9 "MIME-Version: 1.0\n" 11 10 "Content-Type: text/plain; charset=UTF-8\n" 12 11 "Content-Transfer-Encoding: 8bit\n" 13 "Plural-Forms: nplurals=2; plural=(n != 1);\n" 14 "X-Generator: Poedit 3.9\n" 15 "X-Poedit-KeywordsList: " 16 "gettext;gettext_noop;__;_e;esc_attr__;esc_attr_e;esc_html__;esc_html_e;_x;_n\n" 17 "X-Poedit-Basepath: ..\n" 18 "X-Poedit-SourceCharset: UTF-8\n" 19 "X-Poedit-SearchPath-0: .\n" 20 "X-Poedit-SearchPathExcluded-0: node_modules\n" 21 22 #: blocks/most-viewed-posts/index.js:1 blocks/post-views/index.js:1 12 "POT-Creation-Date: 2026-10-07T18:29:06+00:00\n" 13 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 "X-Generator: WP-CLI 2.12.0\n" 15 "X-Domain: post-views-counter\n" 16 17 #. translators: %s: request parameter name 18 #: class-admin.php:95 19 #, php-format 20 msgid "%s must be a positive whole number." 21 msgstr "" 22 23 #. translators: %s: request parameter name 24 #: class-admin.php:114 25 #, php-format 26 msgid "%s must be a whole number." 27 msgstr "" 28 29 #: class-admin.php:130 30 #: class-admin.php:136 31 #: class-columns.php:169 32 msgid "You are not allowed to edit this item." 33 msgstr "" 34 35 #: class-admin.php:133 36 #: class-columns-modal.php:171 37 #: class-columns.php:166 38 #: class-counter.php:556 39 msgid "Invalid post ID." 40 msgstr "" 41 42 #: class-admin.php:154 43 #: class-columns.php:177 44 msgid "The counter totals could not be saved." 45 msgstr "" 46 47 #: class-admin.php:164 48 msgid "No counter totals were submitted." 49 msgstr "" 50 51 #: class-admin.php:220 52 #: class-columns-modal.php:242 53 #: class-columns.php:363 54 #: class-columns.php:370 55 #: class-columns.php:375 56 #: class-columns.php:648 57 #: class-columns.php:723 58 #: class-columns.php:798 59 #: class-dashboard.php:1226 60 #: class-settings-display.php:97 61 msgid "Views" 62 msgstr "" 63 64 #. translators: 1: metric name, 2: formatted count 65 #: class-admin.php:222 66 #: class-columns.php:731 67 #, php-format 68 msgid "%1$s: %2$s." 69 msgstr "" 70 71 #: class-admin.php:223 72 #: class-columns.php:380 73 msgid "Lifetime totals. Changing them does not alter daily, weekly, monthly, or yearly history." 74 msgstr "" 75 76 #: class-admin.php:224 77 #: class-columns.php:384 78 msgid "Cancel" 79 msgstr "" 80 81 #: class-admin.php:225 82 msgid "Views could not be saved." 83 msgstr "" 84 85 #: class-columns-modal.php:95 86 msgid "Loading..." 87 msgstr "" 88 89 #: class-columns-modal.php:96 90 #: class-columns-modal.php:361 91 msgid "Close" 92 msgstr "" 93 94 #: class-columns-modal.php:97 95 msgid "An error occurred while loading data." 96 msgstr "" 97 98 #: class-columns-modal.php:98 99 #: class-columns-modal.php:366 100 msgid "Views in this period:" 101 msgstr "" 102 103 #: class-columns-modal.php:99 104 #: class-dashboard.php:121 105 msgid "Retry" 106 msgstr "" 107 108 #: class-columns-modal.php:100 109 msgid "view" 110 msgstr "" 111 112 #: class-columns-modal.php:101 113 #: class-emails-template.php:1610 114 msgid "views" 115 msgstr "" 116 117 #: class-columns-modal.php:161 118 #: class-columns.php:987 119 msgid "Permission denied." 120 msgstr "" 121 122 #: class-columns-modal.php:177 123 msgid "Post not found." 124 msgstr "" 125 126 #: class-columns-modal.php:181 127 msgid "Admin column disabled." 128 msgstr "" 129 130 #: class-columns-modal.php:185 131 msgid "Post type is not tracked." 132 msgstr "" 133 134 #: class-columns-modal.php:189 135 #: class-columns-modal.php:193 136 msgid "Access denied for this post." 137 msgstr "" 138 139 #: class-columns-modal.php:197 140 msgid "Invalid period." 141 msgstr "" 142 143 #: class-columns-modal.php:371 144 #: class-dashboard.php:337 145 msgid "Chart period" 146 msgstr "" 147 148 #: class-columns-modal.php:372 149 msgid "Year" 150 msgstr "" 151 152 #: class-columns-modal.php:373 153 msgid "Month" 154 msgstr "" 155 156 #: class-columns-modal.php:374 157 msgid "Week" 158 msgstr "" 159 160 #: class-columns-modal.php:385 161 msgid "More insights available" 162 msgstr "" 163 164 #: class-columns-modal.php:386 165 msgid "Upgrade to Pro to unlock it" 166 msgstr "" 167 168 #: class-columns.php:174 169 #: class-columns.php:977 170 msgid "Invalid counter totals." 171 msgstr "" 172 173 #: class-columns.php:185 174 msgid "The saved counter totals could not be read back." 175 msgstr "" 176 177 #: class-columns.php:370 178 #: class-dashboard.php:1258 179 msgid "Edit" 180 msgstr "" 181 182 #: class-columns.php:383 183 msgid "OK" 184 msgstr "" 185 186 #: class-columns.php:675 187 msgid "(no title)" 188 msgstr "" 189 190 #: class-columns.php:736 191 #, php-format 192 msgid "Total Views: %s" 193 msgstr "" 194 195 #: class-columns.php:737 196 #, php-format 197 msgid "%1$s: %2$s. Open chart." 198 msgstr "" 199 200 #: class-columns.php:748 201 msgid "View statistics are restricted." 202 msgstr "" 203 204 #: class-columns.php:931 205 #, php-format 206 msgid "Counter totals updated for %s post." 207 msgid_plural "Counter totals updated for %s posts." 208 msgstr[0] "" 209 msgstr[1] "" 210 211 #: class-columns.php:934 212 #, php-format 213 msgid "Counter totals could not be updated for %s post." 214 msgid_plural "Counter totals could not be updated for %s posts." 215 msgstr[0] "" 216 msgstr[1] "" 217 218 #: class-counter.php:82 219 msgid "Missing or invalid queue parameters." 220 msgstr "" 221 222 #: class-counter.php:89 223 msgid "Security check failed." 224 msgstr "" 225 226 #: class-counter.php:102 227 msgid "No valid post IDs were provided." 228 msgstr "" 229 230 #: class-counter.php:549 231 msgid "REST API method is disabled." 232 msgstr "" 233 234 #: class-counter.php:563 235 msgid "Post type excluded." 236 msgstr "" 237 238 #: class-counter.php:570 239 msgid "Invalid storage type." 240 msgstr "" 241 242 #: class-counter.php:3444 243 #: class-counter.php:3453 244 #: class-counter.php:3466 245 msgid "The requested PVC metric is not supported." 246 msgstr "" 247 248 #: class-counter.php:3458 249 msgid "Too many PVC metric targets were requested." 250 msgstr "" 251 252 #: class-counter.php:3638 253 msgid "You do not have permission to count post views via REST API." 254 msgstr "" 255 256 #: class-cron.php:99 257 msgid "Post Views Counter reset daily counts interval" 258 msgstr "" 259 260 #: class-dashboard.php:95 261 #: class-dashboard.php:140 262 #: class-settings.php:633 263 msgid "Post Views" 264 msgstr "" 265 266 #: class-dashboard.php:120 267 msgid "Failed to load this widget." 268 msgstr "" 269 270 #: class-dashboard.php:141 271 msgid "Displays a chart of most viewed post types." 272 msgstr "" 273 274 #: class-dashboard.php:152 275 msgid "Top Posts" 276 msgstr "" 277 278 #: class-dashboard.php:153 279 msgid "Displays a list of most viewed single posts or pages." 280 msgstr "" 281 282 #: class-dashboard.php:235 283 msgid "More Insights" 284 msgstr "" 285 286 #: class-dashboard.php:237 287 msgid "Go beyond basic post views." 288 msgstr "" 289 290 #: class-dashboard.php:238 291 msgid "See site views, referrers, popular searches, top users, and more." 292 msgstr "" 293 294 #: class-dashboard.php:240 295 msgid "Unlock more insights" 296 msgstr "" 297 298 #: class-dashboard.php:246 299 msgid "Powered by" 300 msgstr "" 301 302 #: class-dashboard.php:291 303 msgid "Chart metrics" 304 msgstr "" 305 306 #: class-dashboard.php:301 307 msgid "Chart datasets" 308 msgstr "" 309 310 #: class-dashboard.php:337 311 #: class-settings-display.php:141 312 #: class-widgets.php:171 313 msgid "Views Period" 314 msgstr "" 315 316 #: class-dashboard.php:338 317 msgid "Yearly" 318 msgstr "" 319 320 #: class-dashboard.php:339 321 #: class-settings-emails.php:91 322 msgid "Monthly" 323 msgstr "" 324 325 #: class-dashboard.php:340 326 #: class-settings-emails.php:90 327 msgid "Weekly" 328 msgstr "" 329 330 #: class-dashboard.php:633 331 msgctxt "dashboard chart metric" 332 msgid "Views" 333 msgstr "" 334 335 #: class-dashboard.php:641 336 msgctxt "dashboard chart metric" 337 msgid "Visits" 338 msgstr "" 339 340 #: class-dashboard.php:657 341 #: class-dashboard.php:1147 342 #: class-dashboard.php:1320 343 msgid "You do not have permission to access this page." 344 msgstr "" 345 346 #: class-dashboard.php:769 347 #: class-settings-display.php:150 348 #: class-widgets.php:85 349 #: functions.php:1022 350 #: post-views-counter.php:534 351 msgid "Total Views" 352 msgstr "" 353 354 #: class-dashboard.php:881 355 msgid "Total Visits" 356 msgstr "" 357 358 #: class-dashboard.php:1005 359 msgid "This month is level with the same days last month." 360 msgstr "" 361 362 #. translators: 1: the month the chart shows, e.g. June 2026, 2: the month before it 363 #: class-dashboard.php:1007 364 #, php-format 365 msgid "%1$s was level with %2$s." 366 msgstr "" 367 368 #: class-dashboard.php:1015 369 msgid "less than 1%" 370 msgstr "" 371 372 #. translators: %s: a change in percent, a whole number without a sign 373 #: class-dashboard.php:1018 374 #, php-format 375 msgid "%s%%" 376 msgstr "" 377 378 #. translators: %s: the change, e.g. 12% 379 #: class-dashboard.php:1023 380 #, php-format 381 msgid "This month is %s higher than the same days last month." 382 msgstr "" 383 384 #. translators: %s: the change, e.g. 12% 385 #: class-dashboard.php:1025 386 #, php-format 387 msgid "This month is %s lower than the same days last month." 388 msgstr "" 389 390 #. translators: 1: the month the chart shows, e.g. June 2026, 2: the change, e.g. 12%, 3: the month before it 391 #: class-dashboard.php:1029 392 #, php-format 393 msgid "%1$s was %2$s higher than %3$s." 394 msgstr "" 395 396 #. translators: 1: the month the chart shows, e.g. June 2026, 2: the change, e.g. 12%, 3: the month before it 397 #: class-dashboard.php:1031 398 #, php-format 399 msgid "%1$s was %2$s lower than %3$s." 400 msgstr "" 401 402 #: class-dashboard.php:1058 403 msgctxt "dashboard comparison: a month" 404 msgid "F Y" 405 msgstr "" 406 407 #: class-dashboard.php:1134 408 msgid "Visit data is not available right now." 409 msgstr "" 410 411 #: class-dashboard.php:1225 412 msgid "Post" 413 msgstr "" 414 415 #: class-dashboard.php:1271 416 #: functions.php:1013 417 msgid "No most viewed posts found." 418 msgstr "" 419 420 #: class-emails-mailer.php:169 421 msgid "WordPress could not send the content views summary email." 422 msgstr "" 423 424 #: class-emails-mailer.php:229 425 msgid "The content views summary recipient is invalid." 426 msgstr "" 427 428 #: class-emails-mailer.php:307 429 msgid "Pending view counts could not be flushed before the summary query." 430 msgstr "" 431 432 #: class-emails-mailer.php:892 433 #, php-format 434 msgid "Post Views Counter on %s" 435 msgstr "" 436 437 #: class-emails-scheduler.php:46 438 msgid "Post Views Counter weekly email summary interval" 439 msgstr "" 440 441 #. Plugin Name of the plugin 442 #: class-emails-template.php:506 443 #: class-emails-template.php:880 444 #: class-settings.php:273 445 #: class-settings.php:632 446 #: class-settings.php:633 447 #: post-views-counter.php 448 msgid "Post Views Counter" 449 msgstr "" 450 451 #: class-emails-template.php:1146 452 #: class-emails-template.php:1188 453 msgid "Content views" 454 msgstr "" 455 456 #: class-emails-template.php:1148 457 #: class-emails-template.php:1175 458 #, php-format 459 msgid "%s total views" 460 msgstr "" 461 462 #: class-emails-template.php:1158 463 #: class-emails-template.php:1185 464 #, php-format 465 msgid "%s content items received views" 466 msgstr "" 467 468 #: class-emails-template.php:1205 469 #: class-emails-template.php:1228 470 msgid "No top content was available for this period." 471 msgstr "" 472 473 #: class-emails-template.php:1207 474 #: class-emails-template.php:1242 475 msgid "Top content" 476 msgstr "" 477 478 #: class-emails-template.php:1210 479 #: class-emails-template.php:1233 480 msgid "(Untitled)" 481 msgstr "" 482 483 #: class-emails-template.php:1212 484 #, php-format 485 msgid "%1$s. %2$s - %3$s views" 486 msgstr "" 487 488 #: class-emails-template.php:1238 489 #, php-format 490 msgid "%s views" 491 msgstr "" 492 493 #: class-emails-template.php:1268 494 #: class-emails-template.php:1301 495 #: class-emails-template.php:1306 496 msgid "Traffic signals" 497 msgstr "" 498 499 #: class-emails-template.php:1297 500 #: class-emails-template.php:1375 501 #, php-format 502 msgid "Unusual traffic activity was detected for %s." 503 msgstr "" 504 505 #: class-emails-template.php:1318 506 #, php-format 507 msgid "Manage Emails in WordPress: %s" 508 msgstr "" 509 510 #: class-emails-template.php:1330 511 msgid "Manage Emails in WordPress" 512 msgstr "" 513 514 #: class-emails-template.php:1340 515 #, php-format 516 msgid "Visit your site: %s" 517 msgstr "" 518 519 #: class-emails-template.php:1351 520 msgid "your site" 521 msgstr "" 522 523 #: class-emails-template.php:1353 524 #, php-format 525 msgid "Visit %s" 526 msgstr "" 527 528 #: class-emails-template.php:1377 529 msgid "Unusual traffic activity was detected during this report period." 530 msgstr "" 531 532 #: class-emails-template.php:1380 533 msgid "No unusual traffic activity was detected during this report period." 534 msgstr "" 535 536 #: class-emails-template.php:1418 537 msgid "day" 538 msgstr "" 539 540 #: class-emails-template.php:1421 541 msgid "month" 542 msgstr "" 543 544 #: class-emails-template.php:1424 545 msgid "week" 546 msgstr "" 547 548 #: class-emails-template.php:1469 549 msgid "weekly" 550 msgstr "" 551 552 #: class-emails-template.php:1484 553 msgid "Weekly Content Views Summary" 554 msgstr "" 555 556 #: class-emails-template.php:1643 557 #, php-format 558 msgid "No previous %s comparison is available yet" 559 msgstr "" 560 561 #: class-emails-template.php:1649 562 #, php-format 563 msgid "No change from the previous %s" 564 msgstr "" 565 566 #: class-emails-template.php:1654 567 #, php-format 568 msgid "Up %1$s views from the previous %2$s" 569 msgstr "" 570 571 #: class-emails-template.php:1656 572 #, php-format 573 msgid "Down %1$s views from the previous %2$s" 574 msgstr "" 575 576 #: class-frontend.php:366 577 msgid "Views:" 578 msgstr "" 579 580 #: class-import.php:67 581 msgid "Custom Meta Key" 582 msgstr "" 583 584 #: class-import.php:208 585 msgid "Override existing views" 586 msgstr "" 587 588 #: class-import.php:209 589 msgid "Replace stored counts with the imported values." 590 msgstr "" 591 592 #: class-import.php:214 593 msgid "Merge with existing views" 594 msgstr "" 595 596 #: class-import.php:215 597 msgid "Add imported counts on top of the existing values." 598 msgstr "" 599 600 #: class-import.php:220 601 msgid "Skip Existing" 602 msgstr "" 603 604 #: class-import.php:221 605 msgid "Only import data when the target record does not exist yet." 606 msgstr "" 607 608 #: class-import.php:226 609 msgid "Keep Higher Count" 610 msgstr "" 611 612 #: class-import.php:227 613 msgid "Keep whichever value is higher when comparing imported and stored counts." 614 msgstr "" 615 616 #: class-import.php:232 617 msgid "Fill Empty Counts" 618 msgstr "" 619 620 #: class-import.php:233 621 msgid "Only import data for posts or periods that currently store zero views." 622 msgstr "" 623 624 #: class-import.php:331 625 msgctxt "view_counts" 626 msgid "total" 627 msgstr "" 628 629 #: class-import.php:334 630 msgctxt "view_counts" 631 msgid "yearly" 632 msgstr "" 633 634 #: class-import.php:337 635 msgctxt "view_counts" 636 msgid "monthly" 637 msgstr "" 638 639 #: class-import.php:340 640 msgctxt "view_counts" 641 msgid "weekly" 642 msgstr "" 643 644 #: class-import.php:343 645 msgctxt "view_counts" 646 msgid "daily" 647 msgstr "" 648 649 #: class-import.php:348 650 msgctxt "view_counts" 651 msgid "post types" 652 msgstr "" 653 654 #: class-import.php:361 655 #, php-format 656 msgid "Imports %s view counts for %s" 657 msgstr "" 658 659 #: class-import.php:363 660 #, php-format 661 msgid "Imports %s view counts" 662 msgstr "" 663 664 #: class-import.php:402 665 msgctxt "view_counts" 666 msgid "and" 667 msgstr "" 668 669 #: class-import.php:428 670 msgid "Invalid import provider selected." 671 msgstr "" 672 673 #: class-import.php:594 674 msgid "Enter the meta key from which the views data is to be retrieved during import." 675 msgstr "" 676 677 #: class-import.php:636 678 #: class-import.php:783 679 msgid "The source data could not be analyzed because a database operation failed." 680 msgstr "" 681 682 #: class-import.php:645 683 #: class-import.php:794 684 #: class-import.php:1067 685 #: class-import.php:1439 686 #, php-format 687 msgid "No valid views data found for %s." 688 msgstr "" 689 690 #: class-import.php:645 691 #, php-format 692 msgid "meta key: %s" 693 msgstr "" 694 695 #: class-import.php:653 696 #: class-import.php:719 697 #, php-format 698 msgid "Meta key \"%s\"." 699 msgstr "" 700 701 #: class-import.php:686 702 #: class-import.php:832 703 #: class-import.php:1071 704 #: class-import.php:1440 705 msgid "No valid post data found to import." 706 msgstr "" 707 708 #: class-import.php:1052 709 msgid "The Statify source could not be analyzed because a database operation failed." 710 msgstr "" 711 712 #: class-import.php:1075 713 msgid "No post types are selected for tracking in settings." 714 msgstr "" 715 716 #: class-import.php:1142 717 #, php-format 718 msgid "Would skip %s non-post URLs." 719 msgstr "" 720 721 #: class-import.php:1142 722 #, php-format 723 msgid "Skipped %s non-post URLs." 724 msgstr "" 725 726 #: class-import.php:1431 727 msgid "The Page Views Count source could not be analyzed because a database operation failed." 728 msgstr "" 729 730 #: class-import.php:2078 731 msgid "The import stopped after a database error. Verify destination totals and restore a database backup before retrying or correcting the import." 732 msgstr "" 733 734 #: class-import.php:2081 735 msgid "The database transaction outcome could not be confirmed, so part of this import may have been stored." 736 msgstr "" 737 738 #: class-import.php:2084 739 #, php-format 740 msgid "Support reference: %s." 741 msgstr "" 742 743 #: class-import.php:2264 744 #, php-format 745 msgid "Analysis of %s:" 746 msgstr "" 747 748 #: class-import.php:2266 749 #, php-format 750 msgid "Import from %s:" 751 msgstr "" 752 753 #: class-import.php:2273 754 msgid "No post view data was found. The valid source rows map to other content types." 755 msgstr "" 756 757 #: class-import.php:2275 758 msgid "No post view data was imported. The valid source rows map to other content types." 759 msgstr "" 760 761 #: class-import.php:2280 762 #, php-format 763 msgid "Found period view data for %s posts, but no valid source total rows." 764 msgstr "" 765 766 #: class-import.php:2285 767 #, php-format 768 msgid "Imported period view data for %s posts; no valid source total rows were available." 769 msgstr "" 770 771 #: class-import.php:2292 772 #, php-format 773 msgid "Found %s total views for %s posts." 774 msgstr "" 775 776 #: class-import.php:2298 777 #, php-format 778 msgid "Successfully imported %s total views for %s posts." 779 msgstr "" 780 781 #: class-import.php:2309 782 #, php-format 783 msgid "Also found period view data for %s additional posts without source totals." 784 msgstr "" 785 786 #: class-import.php:2314 787 #, php-format 788 msgid "Also imported period view data for %s additional posts without source totals." 789 msgstr "" 790 791 #: class-import.php:2327 792 #, php-format 793 msgid "Skipped %1$s total views for %2$s posts." 794 msgstr "" 795 796 #: class-integrations.php:110 797 msgid "Integrate with WordPress block editor to order posts by views in Query Loop and Latest Posts blocks." 798 msgstr "" 799 800 #: class-integrations.php:117 801 msgid "Query Loop Block" 802 msgstr "" 803 804 #: class-integrations.php:118 805 msgid "Enables ordering posts by view count in the core Query Loop block." 806 msgstr "" 807 808 #: class-integrations.php:122 809 msgid "Latest Posts Block" 810 msgstr "" 811 812 #: class-integrations.php:123 813 msgid "Enables ordering posts by view count in the core Latest Posts block." 814 msgstr "" 815 816 #: class-integrations.php:130 817 msgid "Integrate with AMP plugin to handle post views on AMP pages." 818 msgstr "" 819 820 #: class-integrations.php:137 821 msgid "AMP Support" 822 msgstr "" 823 824 #: class-integrations.php:138 825 msgid "Tracks and displays views on AMP-enabled pages." 826 msgstr "" 827 828 #: class-integrations.php:145 829 msgid "Integrate with Beaver Builder to order module posts by views." 830 msgstr "" 831 832 #: class-integrations.php:152 833 msgid "Post Grid Module" 834 msgstr "" 835 836 #: class-integrations.php:153 837 msgid "Orders posts by views in the Beaver Builder Post Grid module." 838 msgstr "" 839 840 #: class-integrations.php:157 841 msgid "Post Carousel Module" 842 msgstr "" 843 844 #: class-integrations.php:158 845 msgid "Orders posts by views in the Beaver Builder Post Carousel module." 846 msgstr "" 847 848 #: class-integrations.php:162 849 #: class-integrations.php:202 850 msgid "Post Slider Module" 851 msgstr "" 852 853 #: class-integrations.php:163 854 msgid "Orders posts by views in the Beaver Builder Post Slider module." 855 msgstr "" 856 857 #: class-integrations.php:170 858 msgid "Integrate with CoBlocks to order post feed results by views." 859 msgstr "" 860 861 #: class-integrations.php:177 862 #: class-integrations.php:282 863 msgid "Posts Block" 864 msgstr "" 865 866 #: class-integrations.php:178 867 msgid "Adds post views ordering to the CoBlocks Posts block." 868 msgstr "" 869 870 #: class-integrations.php:182 871 msgid "Post Carousel Block" 872 msgstr "" 873 874 #: class-integrations.php:183 875 msgid "Adds post views ordering to the CoBlocks Post Carousel block." 876 msgstr "" 877 878 #: class-integrations.php:190 879 msgid "Integrate with Divi Theme to order module posts by views when the module uses the \"orderby-post-views\" CSS class." 880 msgstr "" 881 882 #: class-integrations.php:197 883 msgid "Blog Module" 884 msgstr "" 885 886 #: class-integrations.php:198 887 msgid "Orders posts by views in the Divi Blog module." 888 msgstr "" 889 890 #: class-integrations.php:203 891 msgid "Orders posts by views in the Divi Post Slider module." 892 msgstr "" 893 894 #: class-integrations.php:207 895 msgid "Portfolio Module" 896 msgstr "" 897 898 #: class-integrations.php:208 899 msgid "Orders posts by views in the Divi Portfolio module." 900 msgstr "" 901 902 #: class-integrations.php:215 903 msgid "Integrate with Elementor Pro to order posts by views when a widget query uses the \"post_views\" Query ID." 904 msgstr "" 905 906 #: class-integrations.php:222 907 msgid "Posts Widget" 908 msgstr "" 909 910 #: class-integrations.php:223 911 msgid "Orders posts by views in the Elementor Pro Posts widget when its Query ID is set to \"post_views\"." 912 msgstr "" 913 914 #: class-integrations.php:227 915 msgid "Portfolio Widget" 916 msgstr "" 917 918 #: class-integrations.php:228 919 msgid "Orders items by views in the Elementor Pro Portfolio widget when its Query ID is set to \"post_views\"." 920 msgstr "" 921 922 #: class-integrations.php:232 923 msgid "Loop Grid / Loop Carousel" 924 msgstr "" 925 926 #: class-integrations.php:233 927 msgid "Orders items by views in the Elementor Pro Loop Grid and Loop Carousel widgets when the Query ID is set to \"post_views\"." 928 msgstr "" 929 930 #: class-integrations.php:240 931 msgid "Integrate with GenerateBlocks to order Query block results by views." 932 msgstr "" 933 934 #: class-integrations.php:247 935 msgid "Dynamic Content" 936 msgstr "" 937 938 #: class-integrations.php:248 939 msgid "Adds post_views ordering to the GenerateBlocks Query block." 940 msgstr "" 941 942 #: class-integrations.php:255 943 msgid "Integrate with JetEngine plugin to display post views in custom listings and queries." 944 msgstr "" 945 946 #: class-integrations.php:262 947 msgid "Query Builder" 948 msgstr "" 949 950 #: class-integrations.php:263 951 msgid "Enables ordering posts by view count in Query Builder posts queries." 952 msgstr "" 953 954 #: class-integrations.php:267 955 msgid "Listing Grid" 956 msgstr "" 957 958 #: class-integrations.php:268 959 msgid "Enables ordering posts by view count in Listing Grid, Maps Listing and Calendar widgets." 960 msgstr "" 961 962 #: class-integrations.php:275 963 msgid "Integrate with Kadence Blocks to order post results by views in the Posts block." 964 msgstr "" 965 966 #: class-integrations.php:283 967 msgid "Adds post views ordering to the Posts block." 968 msgstr "" 969 970 #: class-integrations.php:290 971 msgid "Integrate with Polylang to filter reports, exports, and dashboard widgets by language." 972 msgstr "" 973 974 #: class-integrations.php:297 975 #: class-integrations.php:317 976 msgid "Reports Language Filters" 977 msgstr "" 978 979 #: class-integrations.php:298 980 #: class-integrations.php:318 981 msgid "Adds language filtering and a language column to Reports tables, charts, and exports." 982 msgstr "" 983 984 #: class-integrations.php:302 985 #: class-integrations.php:322 986 msgid "Dashboard Widgets" 987 msgstr "" 988 989 #: class-integrations.php:303 990 #: class-integrations.php:323 991 msgid "Filters dashboard widgets (site, post, and term views) by the selected language." 992 msgstr "" 993 994 #: class-integrations.php:310 995 msgid "Integrate with WPML to filter reports, exports, and dashboard widgets by language." 996 msgstr "" 997 998 #: class-settings-display.php:41 999 msgid "Counter Appearance" 1000 msgstr "" 1001 1002 #: class-settings-display.php:46 1003 msgid "Display Targets" 1004 msgstr "" 1005 1006 #: class-settings-display.php:51 1007 msgid "Display Audience" 1008 msgstr "" 1009 1010 #: class-settings-display.php:56 1011 msgid "Admin Interface" 1012 msgstr "" 1013 1014 #: class-settings-display.php:72 1015 msgid "This custom format currently displays no counter." 1016 msgstr "" 1017 1018 #: class-settings-display.php:78 1019 msgid "Guests" 1020 msgstr "" 1021 1022 #: class-settings-display.php:79 1023 msgid "All logged-in users" 1024 msgstr "" 1025 1026 #: class-settings-display.php:80 1027 msgid "Selected user roles" 1028 msgstr "" 1029 1030 #: class-settings-display.php:89 1031 msgid "Display Format" 1032 msgstr "" 1033 1034 #. translators: %s: [post-views] shortcode 1035 #: class-settings-display.php:94 1036 #, php-format 1037 msgid "Choose the format of the counter inserted automatically on the frontend. A manually placed %s shortcode keeps the Views format." 1038 msgstr "" 1039 1040 #: class-settings-display.php:98 1041 msgid "Custom format" 1042 msgstr "" 1043 1044 #: class-settings-display.php:103 1045 #: class-settings-display.php:107 1046 msgid "Custom Format" 1047 msgstr "" 1048 1049 #. translators: 1: views token, 2: icon token 1050 #: class-settings-display.php:109 1051 #, php-format 1052 msgid "Build the counter with %1$s (the view count) and %2$s (the counter icon). Safe HTML is allowed. A format without %1$s displays nothing." 1053 msgstr "" 1054 1055 #: class-settings-display.php:122 1056 msgid "Views Label" 1057 msgstr "" 1058 1059 #: class-settings-display.php:126 1060 msgid "Text shown next to the view count." 1061 msgstr "" 1062 1063 #: class-settings-display.php:147 1064 msgid "Time range used when displaying the number of views." 1065 msgstr "" 1066 1067 #: class-settings-display.php:155 1068 #: class-widgets.php:207 1069 msgid "Display Style" 1070 msgstr "" 1071 1072 #: class-settings-display.php:159 1073 msgid "Choose whether to show an icon, label text, or both." 1074 msgstr "" 1075 1076 #: class-settings-display.php:163 1077 msgid "Icon" 1078 msgstr "" 1079 1080 #: class-settings-display.php:164 1081 msgid "Label" 1082 msgstr "" 1083 1084 #: class-settings-display.php:177 1085 msgid "Icon Class" 1086 msgstr "" 1087 1088 #: class-settings-display.php:197 1089 msgid "Retired. The counter icon no longer uses the Dashicons font. Use the pvc_counter_icon_class filter to supply a custom icon class." 1090 msgstr "" 1091 1092 #: class-settings-display.php:202 1093 msgid "Position" 1094 msgstr "" 1095 1096 #: class-settings-display.php:206 1097 #, php-format 1098 msgid "Where to insert the counter automatically. Use %s shortcode for manual placement." 1099 msgstr "" 1100 1101 #: class-settings-display.php:208 1102 msgid "Before the content" 1103 msgstr "" 1104 1105 #: class-settings-display.php:209 1106 msgid "After the content" 1107 msgstr "" 1108 1109 #: class-settings-display.php:210 1110 msgid "Manual only" 1111 msgstr "" 1112 1113 #: class-settings-display.php:215 1114 msgid "Admin Column" 1115 msgstr "" 1116 1117 #: class-settings-display.php:219 1118 msgid "Show a \"Views\" column on post and page list screens." 1119 msgstr "" 1120 1121 #: class-settings-display.php:223 1122 msgid "Admin Edit" 1123 msgstr "" 1124 1125 #: class-settings-display.php:227 1126 msgid "Allow manual editing of the Views total." 1127 msgstr "" 1128 1129 #: class-settings-display.php:231 1130 msgid "Dynamic Loading" 1131 msgstr "" 1132 1133 #: class-settings-display.php:238 1134 msgid "Load the view count dynamically to avoid caching the displayed value." 1135 msgstr "" 1136 1137 #: class-settings-display.php:243 1138 msgid "Format Number" 1139 msgstr "" 1140 1141 #: class-settings-display.php:246 1142 msgid "Format the view count according to the site locale (uses the WordPress number_format_i18n function)." 1143 msgstr "" 1144 1145 #: class-settings-display.php:250 1146 #: class-settings-general.php:135 1147 msgid "Taxonomies" 1148 msgstr "" 1149 1150 #: class-settings-display.php:257 1151 msgid "Display the view count on category, tag, or custom taxonomy archive pages." 1152 msgstr "" 1153 1154 #: class-settings-display.php:265 1155 msgid "Select taxonomies where the view counter will be displayed." 1156 msgstr "" 1157 1158 #: class-settings-display.php:280 1159 #: class-settings-general.php:147 1160 msgid "Author Archives" 1161 msgstr "" 1162 1163 #: class-settings-display.php:287 1164 msgid "Display the view count on author archive pages." 1165 msgstr "" 1166 1167 #: class-settings-display.php:292 1168 #: class-settings-general.php:127 1169 #: class-widgets.php:160 1170 msgid "Post Types" 1171 msgstr "" 1172 1173 #: class-settings-display.php:295 1174 msgid "Select post types where the view counter will be displayed." 1175 msgstr "" 1176 1177 #: class-settings-display.php:300 1178 msgid "Page Type" 1179 msgstr "" 1180 1181 #: class-settings-display.php:303 1182 msgid "Select page contexts where the view counter will be displayed." 1183 msgstr "" 1184 1185 #: class-settings-display.php:307 1186 msgid "Home" 1187 msgstr "" 1188 1189 #: class-settings-display.php:308 1190 msgid "Archives" 1191 msgstr "" 1192 1193 #: class-settings-display.php:309 1194 msgid "Single posts and pages" 1195 msgstr "" 1196 1197 #: class-settings-display.php:310 1198 msgid "Search results" 1199 msgstr "" 1200 1201 #: class-settings-display.php:316 1202 msgid "User Type" 1203 msgstr "" 1204 1205 #: class-settings-display.php:319 1206 msgid "Hide the automatically inserted counter from the selected visitor groups. Note: selecting both \"Guests\" and \"All logged-in users\" hides the automatic counter from everyone." 1207 msgstr "" 1208 1209 #: class-settings-display.php:340 1210 msgid "User Roles" 1211 msgstr "" 1212 1213 #: class-settings-display.php:343 1214 msgid "Hide the automatically inserted counter from the selected user roles." 1215 msgstr "" 1216 1217 #: class-settings-display.php:353 1218 msgid "Toolbar Chart" 1219 msgstr "" 1220 1221 #: class-settings-display.php:356 1222 msgid "A views chart is shown for content types that are being counted." 1223 msgstr "" 1224 1225 #: class-settings-display.php:357 1226 msgid "Show a views chart in the admin toolbar." 1227 msgstr "" 1228 1229 #: class-settings-display.php:361 1230 msgid "Menu Position" 1231 msgstr "" 1232 1233 #: class-settings-display.php:364 1234 msgid "Top menu" 1235 msgstr "" 1236 1237 #: class-settings-display.php:365 1238 msgid "Settings submenu" 1239 msgstr "" 1240 1241 #: class-settings-display.php:367 1242 msgid "Choose where the plugin menu appears in the admin sidebar." 1243 msgstr "" 1244 1245 #: class-settings-display.php:568 1246 msgid "Choose where the counter is inserted and which content types it attaches to." 1247 msgstr "" 1248 1249 #: class-settings-display.php:577 1250 msgid "Control which visitor groups can see the counter. These rules apply on top of the display targets." 1251 msgstr "" 1252 1253 #: class-settings-display.php:586 1254 msgid "Adjust the label, period, icon, and formatting used when the counter is rendered." 1255 msgstr "" 1256 1257 #: class-settings-display.php:595 1258 msgid "Control how view counts are shown and managed in WordPress admin (columns, edit permissions, toolbar chart)." 1259 msgstr "" 1260 1261 #: class-settings-emails.php:37 1262 msgid "Email Summaries" 1263 msgstr "" 1264 1265 #: class-settings-emails.php:42 1266 msgid "Email Recipients" 1267 msgstr "" 1268 1269 #: class-settings-emails.php:47 1270 msgid "Email Template" 1271 msgstr "" 1272 1273 #: class-settings-emails.php:52 1274 msgid "Test Email" 1275 msgstr "" 1276 1277 #: class-settings-emails.php:57 1278 msgid "Delivery & Status" 1279 msgstr "" 1280 1281 #: class-settings-emails.php:73 1282 msgid "Email Summary" 1283 msgstr "" 1284 1285 #: class-settings-emails.php:76 1286 msgid "Send a summary of tracked content views to the selected recipient." 1287 msgstr "" 1288 1289 #: class-settings-emails.php:80 1290 msgid "Summary Frequency" 1291 msgstr "" 1292 1293 #: class-settings-emails.php:89 1294 msgid "Daily" 1295 msgstr "" 1296 1297 #: class-settings-emails.php:93 1298 msgid "Choose how often views tracking summaries are sent." 1299 msgstr "" 1300 1301 #: class-settings-emails.php:98 1302 msgid "Minimum Tracked Views" 1303 msgstr "" 1304 1305 #: class-settings-emails.php:103 1306 msgid "Do not send the summary if the report period has fewer than this many tracked views." 1307 msgstr "" 1308 1309 #: class-settings-emails.php:109 1310 msgid "Top Content Items" 1311 msgstr "" 1312 1313 #: class-settings-emails.php:114 1314 msgid "Choose how many top content items are included in each summary." 1315 msgstr "" 1316 1317 #: class-settings-emails.php:119 1318 msgid "Top Gainers and Decliners" 1319 msgstr "" 1320 1321 #: class-settings-emails.php:127 1322 msgid "Show which content is gaining or losing momentum compared with previous periods." 1323 msgstr "" 1324 1325 #: class-settings-emails.php:128 1326 msgid "When matching data is available, this appears in the Traffic signals section if the email template includes %%traffic_signals%%." 1327 msgstr "" 1328 1329 #: class-settings-emails.php:132 1330 msgid "Author Summary" 1331 msgstr "" 1332 1333 #: class-settings-emails.php:140 1334 msgid "Include the authors whose content received the most tracked views during the report period." 1335 msgstr "" 1336 1337 #: class-settings-emails.php:141 1338 msgid "When matching data is available, this appears in the Report summary section if the email template includes %%report_summary%%." 1339 msgstr "" 1340 1341 #: class-settings-emails.php:145 1342 msgid "Source Summary" 1343 msgstr "" 1344 1345 #: class-settings-emails.php:153 1346 msgid "Include top referrers or source dimensions when source tracking is available." 1347 msgstr "" 1348 1349 #: class-settings-emails.php:154 1350 msgid "When source tracking data is available, this appears in the Report summary section if the email template includes %%report_summary%%." 1351 msgstr "" 1352 1353 #: class-settings-emails.php:159 1354 msgid "Recipient Email" 1355 msgstr "" 1356 1357 #: class-settings-emails.php:163 1358 msgid "The email address that receives summary emails. Defaults to the site administrator email." 1359 msgstr "" 1360 1361 #: class-settings-emails.php:168 1362 msgid "Additional Recipients" 1363 msgstr "" 1364 1365 #: class-settings-emails.php:176 1366 msgid "Send summaries to multiple people with CC and BCC recipients." 1367 msgstr "" 1368 1369 #: class-settings-emails.php:180 1370 msgid "CC Recipients" 1371 msgstr "" 1372 1373 #: class-settings-emails.php:195 1374 msgid "Send visible copies to additional recipients." 1375 msgstr "" 1376 1377 #: class-settings-emails.php:199 1378 msgid "BCC Recipients" 1379 msgstr "" 1380 1381 #: class-settings-emails.php:214 1382 msgid "Send private copies to additional recipients." 1383 msgstr "" 1384 1385 #: class-settings-emails.php:219 1386 msgid "Email Subject" 1387 msgstr "" 1388 1389 #: class-settings-emails.php:229 1390 msgid "Email Content" 1391 msgstr "" 1392 1393 #: class-settings-emails.php:239 1394 msgid "Send Test To" 1395 msgstr "" 1396 1397 #: class-settings-emails.php:247 1398 msgid "Schedule Status" 1399 msgstr "" 1400 1401 #: class-settings-emails.php:250 1402 msgid "Weekly summaries are scheduled for Monday after the previous full week has ended." 1403 msgstr "" 1404 1405 #: class-settings-emails.php:251 1406 msgid "Summary emails are scheduled with WordPress cron. Delivery time may vary depending on site traffic and hosting configuration." 1407 msgstr "" 1408 1409 #: class-settings-emails.php:256 1410 msgid "Next Scheduled Email" 1411 msgstr "" 1412 1413 #: class-settings-emails.php:264 1414 msgid "Last Sent" 1415 msgstr "" 1416 1417 #: class-settings-emails.php:272 1418 msgid "Last Error" 1419 msgstr "" 1420 1421 #: class-settings-emails.php:287 1422 msgid "Send email summaries with your most viewed content and view totals." 1423 msgstr "" 1424 1425 #: class-settings-emails.php:296 1426 msgid "Choose who should receive your email summaries." 1427 msgstr "" 1428 1429 #: class-settings-emails.php:305 1430 msgid "Review scheduling, delivery, and recent email status information." 1431 msgstr "" 1432 1433 #: class-settings-emails.php:314 1434 msgid "Customize the subject and message used for content views summaries." 1435 msgstr "" 1436 1437 #: class-settings-emails.php:324 1438 msgid "Send a test using the latest available summary. This does not change the saved recipient or scheduled delivery." 1439 msgstr "" 1440 1441 #: class-settings-emails.php:337 1442 msgid "email@example.com" 1443 msgstr "" 1444 1445 #: class-settings-emails.php:337 1446 msgid "Test email recipient" 1447 msgstr "" 1448 1449 #: class-settings-emails.php:338 1450 msgid "Send Test Email" 1451 msgstr "" 1452 1453 #: class-settings-emails.php:338 1454 msgid "Sending..." 1455 msgstr "" 1456 1457 #: class-settings-emails.php:356 1458 msgid "Sorry, you are not allowed to do that." 1459 msgstr "" 1460 1461 #: class-settings-emails.php:395 1462 #: class-settings-emails.php:494 1463 msgid "Enter a valid test recipient email address." 1464 msgstr "" 1465 1466 #: class-settings-emails.php:417 1467 msgid "There is not enough tracked data from the latest complete week to send a real test summary yet." 1468 msgstr "" 1469 1470 #: class-settings-emails.php:437 1471 msgid "The summary test email was sent successfully." 1472 msgstr "" 1473 1474 #: class-settings-emails.php:445 1475 #, php-format 1476 msgid "The test email could not be sent. %s" 1477 msgstr "" 1478 1479 #: class-settings-emails.php:446 1480 msgid "The test email could not be sent. Check your WordPress mail configuration and try again." 1481 msgstr "" 1482 1483 #: class-settings-emails.php:463 1484 msgid "Enter a valid recipient email address for the views summary email." 1485 msgstr "" 1486 1487 #: class-settings-emails.php:469 1488 msgid "Recipient email is required while the views summary email is enabled." 1489 msgstr "" 1490 1491 #: class-settings-emails.php:559 1492 msgid "Minimum tracked views cannot be lower than 0." 1493 msgstr "" 1494 1495 #: class-settings-emails.php:588 1496 #, php-format 1497 msgid "%1$s contained tags that are not available in this field. Removed tags: %2$s. Supported tags here: %3$s" 1498 msgstr "" 1499 1500 #: class-settings-emails.php:711 1501 msgid "Customize the subject line for summary emails." 1502 msgstr "" 1503 1504 #: class-settings-emails.php:713 1505 #, php-format 1506 msgid "Use supported subject tags such as %1$s and %2$s." 1507 msgstr "" 1508 1509 #: class-settings-emails.php:727 1510 msgid "Customize the main message sent with each email summary." 1511 msgstr "" 1512 1513 #: class-settings-emails.php:729 1514 #, php-format 1515 msgid "Use supported content tags such as %s." 1516 msgstr "" 1517 1518 #: class-settings-emails.php:814 1519 msgid "Not sent yet." 1520 msgstr "" 1521 1522 #: class-settings-emails.php:831 1523 msgid "Not scheduled." 1524 msgstr "" 1525 1526 #: class-settings-emails.php:844 1527 msgid "No email errors recorded yet." 1528 msgstr "" 1529 1530 #: class-settings-general.php:54 1531 msgid "PHP" 1532 msgstr "" 1533 1534 #: class-settings-general.php:55 1535 msgid "JavaScript" 1536 msgstr "" 1537 1538 #: class-settings-general.php:56 1539 msgid "REST API" 1540 msgstr "" 1541 1542 #: class-settings-general.php:57 1543 msgid "Fast AJAX" 1544 msgstr "" 1545 1546 #: class-settings-general.php:72 1547 msgid "Tracking Targets" 1548 msgstr "" 1549 1550 #: class-settings-general.php:77 1551 msgid "Tracking Behavior" 1552 msgstr "" 1553 1554 #: class-settings-general.php:82 1555 msgid "Visitor Exclusions" 1556 msgstr "" 1557 1558 #: class-settings-general.php:87 1559 msgid "Performance & Caching" 1560 msgstr "" 1561 1562 #: class-settings-general.php:101 1563 #: class-settings-general.php:452 1564 msgid "minutes" 1565 msgstr "" 1566 1567 #: class-settings-general.php:102 1568 #: class-settings-general.php:217 1569 msgid "hours" 1570 msgstr "" 1571 1572 #: class-settings-general.php:103 1573 msgid "days" 1574 msgstr "" 1575 1576 #: class-settings-general.php:104 1577 msgid "weeks" 1578 msgstr "" 1579 1580 #: class-settings-general.php:105 1581 msgid "months" 1582 msgstr "" 1583 1584 #: class-settings-general.php:106 1585 msgid "years" 1586 msgstr "" 1587 1588 #: class-settings-general.php:111 1589 msgid "crawlers" 1590 msgstr "" 1591 1592 #: class-settings-general.php:112 1593 msgid "AI bots" 1594 msgstr "" 1595 1596 #: class-settings-general.php:113 1597 msgid "logged in users" 1598 msgstr "" 1599 1600 #: class-settings-general.php:114 1601 msgid "guests" 1602 msgstr "" 1603 1604 #: class-settings-general.php:115 1605 msgid "selected user roles" 1606 msgstr "" 1607 1608 #: class-settings-general.php:130 1609 msgid "Select post types whose views should be counted." 1610 msgstr "" 1611 1612 #: class-settings-general.php:138 1613 msgid "Enable counting views on taxonomy term archive pages." 1614 msgstr "" 1615 1616 #: class-settings-general.php:150 1617 msgid "Enable counting views on author archive pages." 1618 msgstr "" 1619 1620 #: class-settings-general.php:159 1621 msgid "Other Pages" 1622 msgstr "" 1623 1624 #: class-settings-general.php:162 1625 msgid "Track views on the front page, post type archives, date archives, search results, 404 pages, and WordPress authentication pages such as login, registration, and password reset." 1626 msgstr "" 1627 1628 #: class-settings-general.php:171 1629 msgid "Traffic Sources" 1630 msgstr "" 1631 1632 #: class-settings-general.php:174 1633 msgid "Collect aggregate stats about visitors' browsers, devices, operating systems and referrers." 1634 msgstr "" 1635 1636 #: class-settings-general.php:183 1637 msgid "Counter Mode" 1638 msgstr "" 1639 1640 #: class-settings-general.php:186 1641 msgid "Choose how views are recorded. If you use caching, select JavaScript, REST API or Fast AJAX (up to <code>10+</code> times faster)." 1642 msgstr "" 1643 1644 #: class-settings-general.php:194 1645 msgid "Data Storage" 1646 msgstr "" 1647 1648 #: class-settings-general.php:199 1649 msgid "Choose how to store the content views data in the user's browser - with or without cookies." 1650 msgstr "" 1651 1652 #: class-settings-general.php:202 1653 msgid "Cookies" 1654 msgstr "" 1655 1656 #: class-settings-general.php:203 1657 msgid "Cookieless" 1658 msgstr "" 1659 1660 #: class-settings-general.php:210 1661 msgid "Count Interval" 1662 msgstr "" 1663 1664 #: class-settings-general.php:223 1665 msgid "Count Time" 1666 msgstr "" 1667 1668 #: class-settings-general.php:229 1669 msgid "Whether to store the views using GMT timezone or adjust it to the GMT offset of the site." 1670 msgstr "" 1671 1672 #: class-settings-general.php:231 1673 msgid "GMT Time" 1674 msgstr "" 1675 1676 #: class-settings-general.php:232 1677 msgid "Local Time" 1678 msgstr "" 1679 1680 #: class-settings-general.php:238 1681 msgid "Strict Counts" 1682 msgstr "" 1683 1684 #: class-settings-general.php:246 1685 msgid "Prevent bypassing the count interval (for example by using incognito mode or clearing cookies)." 1686 msgstr "" 1687 1688 #: class-settings-general.php:251 1689 msgid "Cleanup Interval" 1690 msgstr "" 1691 1692 #: class-settings-general.php:254 1693 #, php-format 1694 msgid "Delete daily content view data older than the period specified above. Enter %s to keep data regardless of age. Cleanup runs once per day." 1695 msgstr "" 1696 1697 #: class-settings-general.php:263 1698 msgid "Caching Compatibility" 1699 msgstr "" 1700 1701 #: class-settings-general.php:278 1702 msgid "Object Cache Support" 1703 msgstr "" 1704 1705 #: class-settings-general.php:293 1706 msgid "Exclude Visitors" 1707 msgstr "" 1708 1709 #: class-settings-general.php:296 1710 msgid "Use this to exclude specific visitor groups from counting views." 1711 msgstr "" 1712 1713 #: class-settings-general.php:307 1714 msgid "Exclude User Roles" 1715 msgstr "" 1716 1717 #: class-settings-general.php:310 1718 msgid "Use this to exclude specific user roles from counting views." 1719 msgstr "" 1720 1721 #: class-settings-general.php:326 1722 msgid "Exclude IPs" 1723 msgstr "" 1724 1725 #: class-settings-general.php:375 1726 msgid "Minimum time between counting new views from the same visitor, in hours. Enter <code>0</code> to count every page view." 1727 msgstr "" 1728 1729 #: class-settings-general.php:453 1730 msgid "Persistent Object Cache" 1731 msgstr "" 1732 1733 #: class-settings-general.php:453 1734 msgid "available" 1735 msgstr "" 1736 1737 #. translators: 1: read state, 2: reason code 1738 #. translators: 1: live write state, 2: reason code 1739 #: class-settings-general.php:453 1740 #: class-visits.php:1874 1741 #: class-visits.php:1875 1742 msgid "unavailable" 1743 msgstr "" 1744 1745 #: class-settings-general.php:454 1746 #, php-format 1747 msgid "How often to flush cached view counts from the object cache into the database. This feature is used only if a persistent object cache like %s or %s is detected and the interval is greater than %s. When used, view counts will be collected and stored in the object cache instead of the database and will then be asynchronously flushed to the database according to the specified interval. The maximum value is %s which means 24 hours.%sNotice:%s Potential data loss may occur if the object cache is cleared/unavailable for the duration of the interval." 1748 msgstr "" 1749 1750 #: class-settings-general.php:533 1751 #: class-settings-general.php:539 1752 msgid "Remove" 1753 msgstr "" 1754 1755 #: class-settings-general.php:547 1756 msgid "Add new" 1757 msgstr "" 1758 1759 #: class-settings-general.php:547 1760 msgid "Add my current IP" 1761 msgstr "" 1762 1763 #: class-settings-general.php:550 1764 msgid "Add IPv4 or IPv6 addresses to exclude them from counting views. Wildcards are supported for IPv4 only (e.g. 192.168.0.*)." 1765 msgstr "" 1766 1767 #: class-settings-general.php:589 1768 msgid "Control which post types, archives and other content types are included in view counting." 1769 msgstr "" 1770 1771 #: class-settings-general.php:598 1772 msgid "Control how views are recorded — counting mode, intervals, time zone, and cleanup." 1773 msgstr "" 1774 1775 #: class-settings-general.php:607 1776 msgid "Exclude specific visitor groups or IP addresses from incrementing view counts." 1777 msgstr "" 1778 1779 #: class-settings-general.php:616 1780 msgid "Configure caching compatibility and object-cache handling for counting." 1781 msgstr "" 1782 1783 #: class-settings-general.php:631 1784 msgid "Currently detected active caching plugins" 1785 msgstr "" 1786 1787 #: class-settings-general.php:639 1788 msgid "No compatible caching plugins found." 1789 msgstr "" 1790 1791 #: class-settings-general.php:651 1792 msgid "Enable compatibility tweaks for supported caching plugins." 1793 msgstr "" 1794 1795 #: class-settings-general.php:655 1796 #: class-settings-general.php:671 1797 #: class-settings-integrations.php:97 1798 msgid "(available)" 1799 msgstr "" 1800 1801 #: class-settings-general.php:667 1802 msgid "Enable Redis or Memcached object cache optimization." 1803 msgstr "" 1804 1805 #: class-settings-general.php:704 1806 msgid "Persistent object cache has been detected." 1807 msgstr "" 1808 1809 #: class-settings-general.php:707 1810 #, php-format 1811 msgid "This feature requires a persistent object cache like %s or %s to be installed and activated." 1812 msgstr "" 1813 1814 #: class-settings-integrations.php:22 1815 #: class-settings.php:653 1816 #: class-settings.php:721 1817 #: class-settings.php:722 1818 msgid "Integrations" 1819 msgstr "" 1820 1821 #: class-settings-integrations.php:65 1822 msgid "Manage available Post Views Counter integrations." 1823 msgstr "" 1824 1825 #: class-settings-other.php:36 1826 msgid "Plugin Status" 1827 msgstr "" 1828 1829 #: class-settings-other.php:41 1830 msgid "Data Import" 1831 msgstr "" 1832 1833 #: class-settings-other.php:46 1834 msgid "Data Removal" 1835 msgstr "" 1836 1837 #: class-settings-other.php:61 1838 msgid "License Key" 1839 msgstr "" 1840 1841 #: class-settings-other.php:66 1842 #, php-format 1843 msgid "Enter your %s license key (requires Pro version to be installed and active)." 1844 msgstr "" 1845 1846 #: class-settings-other.php:73 1847 msgid "Import From" 1848 msgstr "" 1849 1850 #: class-settings-other.php:81 1851 msgid "Import Strategy" 1852 msgstr "" 1853 1854 #: class-settings-other.php:92 1855 msgid "Click Analyse Views to check how many views are available for import, or Import Views to begin the import process." 1856 msgstr "" 1857 1858 #: class-settings-other.php:98 1859 #: class-settings-other.php:275 1860 msgid "Delete Views" 1861 msgstr "" 1862 1863 #: class-settings-other.php:101 1864 msgid "Delete ALL the existing post views data. Note that this is an irreversible process!" 1865 msgstr "" 1866 1867 #: class-settings-other.php:107 1868 msgid "Delete on Deactivation" 1869 msgstr "" 1870 1871 #: class-settings-other.php:110 1872 msgid "When enabled, deactivating the plugin will delete all plugin data from the database, including all content view counts." 1873 msgstr "" 1874 1875 #: class-settings-other.php:111 1876 msgid "Delete all plugin data on deactivation." 1877 msgstr "" 1878 1879 #: class-settings-other.php:156 1880 #, php-format 1881 msgid "%s is not currently available. Please install and activate the required plugin." 1882 msgstr "" 1883 1884 #: class-settings-other.php:166 1885 msgid "Choose a data source to import existing view counts from." 1886 msgstr "" 1887 1888 #: class-settings-other.php:178 1889 #, php-format 1890 msgid "%s is not available. Please install and activate the required plugin to use this import source." 1891 msgstr "" 1892 1893 #: class-settings-other.php:237 1894 msgid "Choose how to handle existing view counts when importing." 1895 msgstr "" 1896 1897 #: class-settings-other.php:262 1898 msgid "Analyse Views" 1899 msgstr "" 1900 1901 #: class-settings-other.php:263 1902 msgid "Import Views" 1903 msgstr "" 1904 1905 #: class-settings-other.php:286 1906 msgid "View license details and other status information." 1907 msgstr "" 1908 1909 #: class-settings-other.php:326 1910 msgid "Active" 1911 msgstr "" 1912 1913 #: class-settings-other.php:328 1914 msgid "Not Detected" 1915 msgstr "" 1916 1917 #. translators: 1: Core version, 2: extension version 1918 #: class-settings-other.php:371 1919 #: class-visits.php:1884 1920 msgid "unknown" 1921 msgstr "" 1922 1923 #: class-settings-other.php:385 1924 msgid "Plugin Version" 1925 msgstr "" 1926 1927 #: class-settings-other.php:393 1928 msgid "Database Tables" 1929 msgstr "" 1930 1931 #: class-settings-other.php:474 1932 msgid "Import view counts when migrating from custom meta key or other analytics plugins." 1933 msgstr "" 1934 1935 #: class-settings-other.php:483 1936 msgid "Choose what happens to stored view data on uninstall, and manage other removal-related tools." 1937 msgstr "" 1938 1939 #: class-settings-reports.php:57 1940 msgid "Display Reports and Export Views to CSV/XML" 1941 msgstr "" 1942 1943 #: class-settings-reports.php:58 1944 msgid "View detailed stats about the popularity of your content." 1945 msgstr "" 1946 1947 #: class-settings-reports.php:59 1948 msgid "Generate views reports in any date range you need." 1949 msgstr "" 1950 1951 #: class-settings-reports.php:60 1952 msgid "Export, download and share your website views data." 1953 msgstr "" 1954 1955 #: class-settings-reports.php:61 1956 #: class-settings.php:192 1957 msgid "Upgrade to Pro" 1958 msgstr "" 1959 1960 #: class-settings.php:193 1961 msgid "Starting from $29 per year" 1962 msgstr "" 1963 1964 #: class-settings.php:193 1965 msgid "14-day money back guarantee." 1966 msgstr "" 1967 1968 #: class-settings.php:210 1969 msgid "Reliable view counting" 1970 msgstr "" 1971 1972 #: class-settings.php:212 1973 msgid "Accurate counts with caching enabled" 1974 msgstr "" 1975 1976 #: class-settings.php:213 1977 msgid "Better performance under high traffic" 1978 msgstr "" 1979 1980 #: class-settings.php:214 1981 msgid "Protection against fake and repeated views" 1982 msgstr "" 1983 1984 #: class-settings.php:216 1985 msgid "Upgrade to Pro to make your view counts reliable on real-world, cached WordPress sites." 1986 msgstr "" 1987 1988 #: class-settings.php:219 1989 msgid "Accurate & meaningful view display" 1990 msgstr "" 1991 1992 #: class-settings.php:221 1993 msgid "Choose which time period is displayed" 1994 msgstr "" 1995 1996 #: class-settings.php:222 1997 msgid "Always show up-to-date view counts" 1998 msgstr "" 1999 2000 #: class-settings.php:223 2001 msgid "Control where the counter appears" 2002 msgstr "" 2003 2004 #: class-settings.php:225 2005 msgid "Upgrade to Pro to control what view data visitors actually see - not just total counts." 2006 msgstr "" 2007 2008 #: class-settings.php:228 2009 msgid "Advanced view reports" 2010 msgstr "" 2011 2012 #: class-settings.php:230 2013 msgid "Upgrade to Pro to access detailed reports and visual insights for your content." 2014 msgstr "" 2015 2016 #: class-settings.php:233 2017 msgid "Use view counts where they actually matter" 2018 msgstr "" 2019 2020 #: class-settings.php:235 2021 msgid "Display and sort content by popularity" 2022 msgstr "" 2023 2024 #: class-settings.php:236 2025 msgid "Works with the tools you already use" 2026 msgstr "" 2027 2028 #: class-settings.php:237 2029 msgid "No custom queries or advanced setup" 2030 msgstr "" 2031 2032 #: class-settings.php:239 2033 msgid "Upgrade to Pro to use view data across layouts and blocks - not just store it." 2034 msgstr "" 2035 2036 #: class-settings.php:242 2037 msgid "Deeper email summaries" 2038 msgstr "" 2039 2040 #: class-settings.php:244 2041 msgid "Spot content gaining or losing momentum" 2042 msgstr "" 2043 2044 #: class-settings.php:245 2045 msgid "Include author and source summaries" 2046 msgstr "" 2047 2048 #: class-settings.php:246 2049 msgid "Send daily or monthly summaries" 2050 msgstr "" 2051 2052 #: class-settings.php:247 2053 msgid "Add CC/BCC recipients for your team" 2054 msgstr "" 2055 2056 #: class-settings.php:249 2057 msgid "Go beyond a weekly top-content list. Pro adds richer summaries with trends, authors, sources, and flexible delivery options." 2058 msgstr "" 2059 2060 #: class-settings.php:252 2061 msgid "Migrate your view data safely" 2062 msgstr "" 2063 2064 #: class-settings.php:254 2065 msgid "Import view data from other WordPress plugins" 2066 msgstr "" 2067 2068 #: class-settings.php:255 2069 msgid "Choose how existing data is handled" 2070 msgstr "" 2071 2072 #: class-settings.php:256 2073 msgid "Support for posts and other content types" 2074 msgstr "" 2075 2076 #: class-settings.php:258 2077 msgid "Upgrade to Pro to migrate historical view data without losing control over existing counts." 2078 msgstr "" 2079 2080 #: class-settings.php:638 2081 #: class-settings.php:691 2082 #: class-settings.php:692 2083 msgid "Counting" 2084 msgstr "" 2085 2086 #: class-settings.php:643 2087 #: class-settings.php:701 2088 #: class-settings.php:702 2089 msgid "Display" 2090 msgstr "" 2091 2092 #: class-settings.php:648 2093 #: class-settings.php:711 2094 #: class-settings.php:712 2095 #: class-settings.php:754 2096 msgid "Reports" 2097 msgstr "" 2098 2099 #: class-settings.php:658 2100 #: class-settings.php:731 2101 #: class-settings.php:732 2102 msgid "Emails" 2103 msgstr "" 2104 2105 #: class-settings.php:663 2106 #: class-settings.php:741 2107 #: class-settings.php:742 2108 msgid "Other" 2109 msgstr "" 2110 2111 #: class-settings.php:1004 2112 msgid "Queued counts cannot be retired safely. Update or deactivate Post Views Counter Pro before retrying." 2113 msgstr "" 2114 2115 #: class-settings.php:1012 2116 #: class-settings.php:1071 2117 msgid "Error occurred. All existing data were not deleted." 2118 msgstr "" 2119 2120 #: class-settings.php:1067 2121 msgid "All existing data deleted successfully." 2122 msgstr "" 2123 2124 #: class-settings.php:1069 2125 msgid "Visits state could not be reset safely, so no data was deleted." 2126 msgstr "" 2127 2128 #: class-settings.php:1170 2129 msgid "NEW!" 2130 msgstr "" 2131 2132 #: class-toolbar.php:134 2133 #, php-format 2134 msgid "%s post view" 2135 msgid_plural "%s post views" 2136 msgstr[0] "" 2137 msgstr[1] "" 2138 2139 #. translators: 1: month and year, 2: total number of post views 2140 #: class-toolbar.php:140 2141 #, php-format 2142 msgid "Post views chart for %1$s, %2$s total" 2143 msgstr "" 2144 2145 #: class-traffic-signals.php:124 2146 msgid "Traffic Signals" 2147 msgstr "" 2148 2149 #: class-traffic-signals.php:166 2150 msgid "No unusual activity detected." 2151 msgstr "" 2152 2153 #: class-traffic-signals.php:172 2154 msgid "Unusual traffic pattern detected. More insights available in Post Views Counter Pro." 2155 msgstr "" 2156 2157 #: class-update.php:241 2158 msgid "<strong>Post Views Counter</strong> - this version requires a database update. Make sure to back up your database first." 2159 msgstr "" 2160 2161 #: class-update.php:242 2162 msgid "Run the Update" 2163 msgstr "" 2164 2165 #: class-update.php:336 2166 msgid "Thank you! Datebase was successfully updated." 2167 msgstr "" 2168 2169 #: class-visits.php:1872 2170 msgid "Visits Readiness" 2171 msgstr "" 2172 2173 #. translators: 1: read state, 2: reason code 2174 #: class-visits.php:1874 2175 #, php-format 2176 msgid "Read: %1$s (%2$s)" 2177 msgstr "" 2178 2179 #. translators: 1: read state, 2: reason code 2180 #. translators: 1: live write state, 2: reason code 2181 #: class-visits.php:1874 2182 #: class-visits.php:1875 2183 msgid "ready" 2184 msgstr "" 2185 2186 #. translators: 1: live write state, 2: reason code 2187 #: class-visits.php:1875 2188 #, php-format 2189 msgid "Live write: %1$s (%2$s)" 2190 msgstr "" 2191 2192 #. translators: 1: schema state, 2: schema status code 2193 #: class-visits.php:1876 2194 #, php-format 2195 msgid "Schema: %1$s (%2$s)" 2196 msgstr "" 2197 2198 #. translators: derived metrics start timestamp or none 2199 #: class-visits.php:1877 2200 #, php-format 2201 msgid "Derived metrics since: %s" 2202 msgstr "" 2203 2204 #. translators: derived metrics start timestamp or none 2205 #: class-visits.php:1877 2206 msgid "none" 2207 msgstr "" 2208 2209 #. translators: 1: last migration attempt timestamp or never, 2: last compatibility check timestamp or never 2210 #: class-visits.php:1880 2211 #, php-format 2212 msgid "Checks: migration attempt %1$s; compatibility %2$s" 2213 msgstr "" 2214 2215 #: class-visits.php:1881 2216 #: class-visits.php:1882 2217 msgid "never" 2218 msgstr "" 2219 2220 #. translators: 1: Core version, 2: extension version 2221 #: class-visits.php:1884 2222 #, php-format 2223 msgid "Versions: Core %1$s; Pro %2$s" 2224 msgstr "" 2225 2226 #. translators: 1: Core version, 2: extension version 2227 #: class-visits.php:1884 2228 msgid "inactive" 2229 msgstr "" 2230 2231 #: class-widgets.php:55 2232 #: class-widgets.php:63 2233 msgid "Most Viewed Posts" 2234 msgstr "" 2235 2236 #: class-widgets.php:57 2237 msgid "Displays a list of the most viewed posts" 2238 msgstr "" 2239 2240 #: class-widgets.php:74 2241 msgid "No most viewed posts found" 2242 msgstr "" 2243 2244 #: class-widgets.php:79 2245 #: blocks/most-viewed-posts/index.js:1 2246 #: src/blocks/most-viewed-posts/edit.js:98 2247 msgid "Ascending" 2248 msgstr "" 2249 2250 #: class-widgets.php:80 2251 #: blocks/most-viewed-posts/index.js:1 2252 #: src/blocks/most-viewed-posts/edit.js:99 2253 msgid "Descending" 2254 msgstr "" 2255 2256 #: class-widgets.php:90 2257 #: blocks/most-viewed-posts/index.js:1 2258 #: src/blocks/most-viewed-posts/edit.js:108 2259 msgid "Unordered list" 2260 msgstr "" 2261 2262 #: class-widgets.php:91 2263 #: blocks/most-viewed-posts/index.js:1 2264 #: src/blocks/most-viewed-posts/edit.js:111 2265 msgid "Ordered list" 2266 msgstr "" 2267 2268 #: class-widgets.php:156 2269 #: blocks/most-viewed-posts/index.js:1 2270 #: src/blocks/most-viewed-posts/edit.js:43 2271 msgid "Title" 2272 msgstr "" 2273 2274 #: class-widgets.php:186 2275 #: blocks/most-viewed-posts/index.js:1 2276 #: src/blocks/most-viewed-posts/edit.js:84 2277 msgid "Number of posts to show" 2278 msgstr "" 2279 2280 #: class-widgets.php:190 2281 #: blocks/most-viewed-posts/index.js:1 2282 #: src/blocks/most-viewed-posts/edit.js:90 2283 msgid "No posts message" 2284 msgstr "" 2285 2286 #: class-widgets.php:194 2287 #: blocks/most-viewed-posts/index.js:1 2288 #: src/blocks/most-viewed-posts/edit.js:95 2289 msgid "Order" 2290 msgstr "" 2291 2292 #: class-widgets.php:220 2293 msgid "Display post views?" 2294 msgstr "" 2295 2296 #: class-widgets.php:222 2297 msgid "Display post excerpt?" 2298 msgstr "" 2299 2300 #: class-widgets.php:224 2301 msgid "Display post author?" 2302 msgstr "" 2303 2304 #: class-widgets.php:226 2305 msgid "Display post thumbnail?" 2306 msgstr "" 2307 2308 #: class-widgets.php:229 2309 #: blocks/most-viewed-posts/index.js:1 2310 #: src/blocks/most-viewed-posts/edit.js:146 2311 msgid "Thumbnail size" 2312 msgstr "" 2313 2314 #. Plugin URI of the plugin 2315 #: post-views-counter.php 2316 msgid "https://postviewscounter.com/" 2317 msgstr "" 2318 2319 #. Description of the plugin 2320 #: post-views-counter.php 2321 msgid "Count and display post views, track site-wide visits, and see what content works – inside WordPress. Fast, easy to use and privacy-first." 2322 msgstr "" 2323 2324 #. Author of the plugin 2325 #: post-views-counter.php 2326 msgid "dFactory" 2327 msgstr "" 2328 2329 #. Author URI of the plugin 2330 #: post-views-counter.php 2331 msgid "https://dfactory.co/" 2332 msgstr "" 2333 2334 #: blocks/most-viewed-posts/index.js:1 2335 #: blocks/post-views/index.js:1 23 2336 #: src/blocks/utils.js:13 24 2337 msgid "Something went wrong. Try again or refresh the page." 25 2338 msgstr "" 26 2339 27 #: blocks/most-viewed-posts/index.js:1 blocks/post-views/index.js:1 28 #: post-views-counter.php:1325 src/blocks/most-viewed-posts/edit.js:40 2340 #: blocks/most-viewed-posts/index.js:1 2341 #: blocks/post-views/index.js:1 2342 #: src/blocks/most-viewed-posts/edit.js:40 29 2343 #: src/blocks/post-views/edit.js:14 2344 #: post-views-counter.php:1500 30 2345 msgid "Settings" 31 2346 msgstr "" 32 2347 33 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:156 34 #: src/blocks/most-viewed-posts/edit.js:43 35 msgid "Title" 36 msgstr "" 37 38 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:46 2348 #: blocks/most-viewed-posts/index.js:1 2349 #: src/blocks/most-viewed-posts/edit.js:46 39 2350 msgid "Enter empty text to hide title." 40 2351 msgstr "" 41 2352 42 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:50 2353 #: blocks/most-viewed-posts/index.js:1 2354 #: src/blocks/most-viewed-posts/edit.js:50 43 2355 msgid "Post types" 44 2356 msgstr "" 45 2357 46 #: blocks/most-viewed-posts/index.js:1 blocks/post-views/index.js:1 47 #: src/blocks/most-viewed-posts/edit.js:77 src/blocks/post-views/edit.js:25 2358 #: blocks/most-viewed-posts/index.js:1 2359 #: blocks/post-views/index.js:1 2360 #: src/blocks/most-viewed-posts/edit.js:77 2361 #: src/blocks/post-views/edit.js:25 48 2362 msgid "Views period" 49 2363 msgstr "" 50 2364 51 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:186 52 #: src/blocks/most-viewed-posts/edit.js:84 53 msgid "Number of posts to show" 54 msgstr "" 55 56 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:190 57 #: src/blocks/most-viewed-posts/edit.js:90 58 msgid "No posts message" 59 msgstr "" 60 61 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:194 62 #: src/blocks/most-viewed-posts/edit.js:95 63 msgid "Order" 64 msgstr "" 65 66 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:79 67 #: src/blocks/most-viewed-posts/edit.js:98 68 msgid "Ascending" 69 msgstr "" 70 71 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:80 72 #: src/blocks/most-viewed-posts/edit.js:99 73 msgid "Descending" 74 msgstr "" 75 76 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:104 2365 #: blocks/most-viewed-posts/index.js:1 2366 #: src/blocks/most-viewed-posts/edit.js:104 77 2367 msgid "Display style" 78 2368 msgstr "" 79 2369 80 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:90 81 #: src/blocks/most-viewed-posts/edit.js:108 82 msgid "Unordered list" 83 msgstr "" 84 85 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:91 86 #: src/blocks/most-viewed-posts/edit.js:111 87 msgid "Ordered list" 88 msgstr "" 89 90 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:117 2370 #: blocks/most-viewed-posts/index.js:1 2371 #: src/blocks/most-viewed-posts/edit.js:117 91 2372 msgid "Display Data" 92 2373 msgstr "" 93 2374 94 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:121 2375 #: blocks/most-viewed-posts/index.js:1 2376 #: src/blocks/most-viewed-posts/edit.js:121 95 2377 msgid "Post views" 96 2378 msgstr "" 97 2379 98 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:127 2380 #: blocks/most-viewed-posts/index.js:1 2381 #: src/blocks/most-viewed-posts/edit.js:127 99 2382 msgid "Post excerpt" 100 2383 msgstr "" 101 2384 102 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:133 2385 #: blocks/most-viewed-posts/index.js:1 2386 #: src/blocks/most-viewed-posts/edit.js:133 103 2387 msgid "Post author" 104 2388 msgstr "" 105 2389 106 #: blocks/most-viewed-posts/index.js:1 src/blocks/most-viewed-posts/edit.js:139 2390 #: blocks/most-viewed-posts/index.js:1 2391 #: src/blocks/most-viewed-posts/edit.js:139 107 2392 msgid "Post thumbnail" 108 2393 msgstr "" 109 2394 110 #: blocks/most-viewed-posts/index.js:1 includes/class-widgets.php:229 111 #: src/blocks/most-viewed-posts/edit.js:146 112 msgid "Thumbnail size" 113 msgstr "" 114 115 #: blocks/post-views/index.js:1 src/blocks/post-views/edit.js:17 2395 #: blocks/post-views/index.js:1 2396 #: src/blocks/post-views/edit.js:17 116 2397 msgid "Post ID" 117 2398 msgstr "" 118 2399 119 #: blocks/post-views/index.js:1 src/blocks/post-views/edit.js:20 2400 #: blocks/post-views/index.js:1 2401 #: src/blocks/post-views/edit.js:20 120 2402 msgid "Enter 0 to use current visited post." 121 2403 msgstr "" 122 2404 123 #: blocks/pro-placeholder/index.js:1 src/blocks/pro-placeholder/index.js:47 2405 #: blocks/pro-placeholder/index.js:1 2406 #: src/blocks/pro-placeholder/index.js:47 124 2407 msgid "This block requires Post Views Counter Pro." 125 2408 msgstr "" 126 2409 127 #: blocks/pro-placeholder/index.js:1 src/blocks/pro-placeholder/index.js:57 2410 #: blocks/pro-placeholder/index.js:1 2411 #: src/blocks/pro-placeholder/index.js:57 128 2412 msgid "Learn More" 129 2413 msgstr "" 130 2414 131 #: includes/class-admin.php:75 includes/class-admin.php:79 132 #: includes/class-admin.php:112 includes/class-admin.php:116 133 msgid "You are not allowed to edit this item." 134 msgstr "" 135 136 #: includes/class-admin.php:108 includes/class-columns-modal.php:101 137 #: includes/class-counter.php:520 138 msgid "Invalid post ID." 139 msgstr "" 140 141 #: includes/class-admin.php:172 includes/class-columns.php:80 142 #: includes/class-columns.php:283 includes/class-columns.php:378 143 #: includes/class-dashboard.php:61 includes/class-dashboard.php:106 144 #: includes/class-settings.php:633 2415 #: src/js/integration-gutenberg.jsx:265 2416 #: src/js/integration-gutenberg.jsx:398 2417 msgid "Most viewed" 2418 msgstr "" 2419 2420 #: src/js/integration-gutenberg.jsx:266 2421 #: src/js/integration-gutenberg.jsx:399 2422 msgid "Least viewed" 2423 msgstr "" 2424 2425 #: src/js/integration-gutenberg.jsx:294 2426 #: src/js/integration-gutenberg.jsx:499 2427 msgid "Post Views Settings" 2428 msgstr "" 2429 2430 #: src/js/integration-gutenberg.jsx:299 2431 #: src/js/integration-gutenberg.jsx:504 2432 msgid "Include posts with zero views" 2433 msgstr "" 2434 2435 #: src/js/integration-gutenberg.jsx:306 2436 #: src/js/integration-gutenberg.jsx:509 2437 msgid "When enabled, posts with no views will be included in the results." 2438 msgstr "" 2439 2440 #: blocks/most-viewed-posts/block.json 2441 #: src/blocks/most-viewed-posts/block.json 2442 msgctxt "block title" 2443 msgid "Most Viewed Posts" 2444 msgstr "" 2445 2446 #: blocks/most-viewed-posts/block.json 2447 #: src/blocks/most-viewed-posts/block.json 2448 msgctxt "block description" 2449 msgid "Displays a list of the most viewed posts." 2450 msgstr "" 2451 2452 #: blocks/most-viewed-posts/block.json 2453 #: blocks/post-views/block.json 2454 #: blocks/pro-placeholder/most-viewed-terms/block.json 2455 #: blocks/pro-placeholder/most-viewed-users/block.json 2456 #: blocks/pro-placeholder/site-views/block.json 2457 #: blocks/pro-placeholder/term-views/block.json 2458 #: blocks/pro-placeholder/user-views/block.json 2459 #: src/blocks/most-viewed-posts/block.json 2460 #: src/blocks/post-views/block.json 2461 msgctxt "block keyword" 2462 msgid "views" 2463 msgstr "" 2464 2465 #: blocks/most-viewed-posts/block.json 2466 #: blocks/pro-placeholder/most-viewed-terms/block.json 2467 #: blocks/pro-placeholder/most-viewed-users/block.json 2468 #: src/blocks/most-viewed-posts/block.json 2469 msgctxt "block keyword" 2470 msgid "popular" 2471 msgstr "" 2472 2473 #: blocks/most-viewed-posts/block.json 2474 #: blocks/post-views/block.json 2475 #: src/blocks/most-viewed-posts/block.json 2476 #: src/blocks/post-views/block.json 2477 msgctxt "block keyword" 2478 msgid "counter" 2479 msgstr "" 2480 2481 #: blocks/most-viewed-posts/block.json 2482 #: blocks/post-views/block.json 2483 #: blocks/pro-placeholder/site-views/block.json 2484 #: src/blocks/most-viewed-posts/block.json 2485 #: src/blocks/post-views/block.json 2486 msgctxt "block keyword" 2487 msgid "analytics" 2488 msgstr "" 2489 2490 #: blocks/most-viewed-posts/block.json 2491 #: src/blocks/most-viewed-posts/block.json 2492 msgctxt "block keyword" 2493 msgid "trending" 2494 msgstr "" 2495 2496 #: blocks/post-views/block.json 2497 #: src/blocks/post-views/block.json 2498 msgctxt "block title" 145 2499 msgid "Post Views" 146 2500 msgstr "" 147 2501 148 #: includes/class-admin.php:173 includes/class-columns.php:96 149 msgid "Adjust the views count for this post." 150 msgstr "" 151 152 #: includes/class-admin.php:174 includes/class-columns.php:101 153 msgid "Cancel" 154 msgstr "" 155 156 #: includes/class-columns-modal.php:70 157 msgid "Loading..." 158 msgstr "" 159 160 #: includes/class-columns-modal.php:71 includes/class-columns-modal.php:264 161 msgid "Close" 162 msgstr "" 163 164 #: includes/class-columns-modal.php:72 165 msgid "An error occurred while loading data." 166 msgstr "" 167 168 #: includes/class-columns-modal.php:73 169 msgid "Total views in this period:" 170 msgstr "" 171 172 #: includes/class-columns-modal.php:74 173 msgid "view" 174 msgstr "" 175 176 #: includes/class-columns-modal.php:75 includes/class-emails-template.php:1610 177 msgid "views" 178 msgstr "" 179 180 #: includes/class-columns-modal.php:91 181 msgid "Permission denied." 182 msgstr "" 183 184 #: includes/class-columns-modal.php:107 185 msgid "Post not found." 186 msgstr "" 187 188 #: includes/class-columns-modal.php:111 189 msgid "Admin column disabled." 190 msgstr "" 191 192 #: includes/class-columns-modal.php:115 193 msgid "Post type is not tracked." 194 msgstr "" 195 196 #: includes/class-columns-modal.php:119 197 msgid "Access denied for this post." 198 msgstr "" 199 200 #: includes/class-columns-modal.php:275 201 msgid "Year" 202 msgstr "" 203 204 #: includes/class-columns-modal.php:276 205 msgid "Month" 206 msgstr "" 207 208 #: includes/class-columns-modal.php:277 209 msgid "Week" 210 msgstr "" 211 212 #: includes/class-columns-modal.php:287 213 msgid "More insights available" 214 msgstr "" 215 216 #: includes/class-columns-modal.php:288 217 msgid "Upgrade to Pro to unlock it" 218 msgstr "" 219 220 #: includes/class-columns.php:92 includes/class-dashboard.php:529 221 msgid "Edit" 222 msgstr "" 223 224 #: includes/class-columns.php:100 225 msgid "OK" 226 msgstr "" 227 228 #: includes/class-columns.php:318 includes/class-dashboard.php:522 229 msgid "(no title)" 230 msgstr "" 231 232 #: includes/class-counter.php:73 233 msgid "Missing or invalid queue parameters." 234 msgstr "" 235 236 #: includes/class-counter.php:80 237 msgid "Security check failed." 238 msgstr "" 239 240 #: includes/class-counter.php:93 241 msgid "No valid post IDs were provided." 242 msgstr "" 243 244 #: includes/class-counter.php:513 245 msgid "REST API method is disabled." 246 msgstr "" 247 248 #: includes/class-counter.php:527 249 msgid "Post type excluded." 250 msgstr "" 251 252 #: includes/class-counter.php:534 253 msgid "Invalid storage type." 254 msgstr "" 255 256 #: includes/class-counter.php:2423 257 msgid "You do not have permission to count post views via REST API." 258 msgstr "" 259 260 #: includes/class-cron.php:69 261 msgid "Post Views Counter reset daily counts interval" 262 msgstr "" 263 264 #: includes/class-dashboard.php:86 265 msgid "Failed to load this widget." 266 msgstr "" 267 268 #: includes/class-dashboard.php:87 269 msgid "Retry" 270 msgstr "" 271 272 #: includes/class-dashboard.php:107 273 msgid "Displays a chart of most viewed post types." 274 msgstr "" 275 276 #: includes/class-dashboard.php:113 277 msgid "Top Posts" 278 msgstr "" 279 280 #: includes/class-dashboard.php:114 281 msgid "Displays a list of most viewed single posts or pages." 282 msgstr "" 283 284 #: includes/class-dashboard.php:196 285 msgid "More Insights" 286 msgstr "" 287 288 #: includes/class-dashboard.php:198 289 msgid "Go beyond basic post views." 290 msgstr "" 291 292 #: includes/class-dashboard.php:199 293 msgid "See site views, referrers, popular searches, top users, and more." 294 msgstr "" 295 296 #: includes/class-dashboard.php:201 297 msgid "Unlock more insights" 298 msgstr "" 299 300 #: includes/class-dashboard.php:207 301 msgid "Powered by" 302 msgstr "" 303 304 #: includes/class-dashboard.php:275 includes/class-dashboard.php:431 305 #: includes/class-dashboard.php:592 306 msgid "You do not have permission to access this page." 307 msgstr "" 308 309 #: includes/class-dashboard.php:326 includes/class-settings-display.php:104 310 #: includes/class-widgets.php:85 includes/functions.php:745 311 #: post-views-counter.php:510 312 msgid "Total Views" 313 msgstr "" 314 315 #: includes/class-dashboard.php:496 316 msgid "Post" 317 msgstr "" 318 319 #: includes/class-dashboard.php:497 320 msgid "Views" 321 msgstr "" 322 323 #: includes/class-dashboard.php:542 includes/functions.php:736 324 msgid "No most viewed posts found." 325 msgstr "" 326 327 #: includes/class-emails-mailer.php:166 328 msgid "WordPress could not send the content views summary email." 329 msgstr "" 330 331 #: includes/class-emails-mailer.php:226 332 msgid "The content views summary recipient is invalid." 333 msgstr "" 334 335 #: includes/class-emails-mailer.php:884 336 #, php-format 337 msgid "Post Views Counter on %s" 338 msgstr "" 339 340 #: includes/class-emails-scheduler.php:46 341 msgid "Post Views Counter weekly email summary interval" 342 msgstr "" 343 344 #: includes/class-emails-template.php:506 345 #: includes/class-emails-template.php:880 includes/class-settings.php:273 346 #: includes/class-settings.php:632 includes/class-settings.php:633 347 msgid "Post Views Counter" 348 msgstr "" 349 350 #: includes/class-emails-template.php:1146 351 #: includes/class-emails-template.php:1188 352 msgid "Content views" 353 msgstr "" 354 355 #: includes/class-emails-template.php:1148 356 #: includes/class-emails-template.php:1175 357 #, php-format 358 msgid "%s total views" 359 msgstr "" 360 361 #: includes/class-emails-template.php:1158 362 #: includes/class-emails-template.php:1185 363 #, php-format 364 msgid "%s content items received views" 365 msgstr "" 366 367 #: includes/class-emails-template.php:1205 368 #: includes/class-emails-template.php:1228 369 msgid "No top content was available for this period." 370 msgstr "" 371 372 #: includes/class-emails-template.php:1207 373 #: includes/class-emails-template.php:1242 374 msgid "Top content" 375 msgstr "" 376 377 #: includes/class-emails-template.php:1210 378 #: includes/class-emails-template.php:1233 379 msgid "(Untitled)" 380 msgstr "" 381 382 #: includes/class-emails-template.php:1212 383 #, php-format 384 msgid "%1$s. %2$s - %3$s views" 385 msgstr "" 386 387 #: includes/class-emails-template.php:1238 388 #, php-format 389 msgid "%s views" 390 msgstr "" 391 392 #: includes/class-emails-template.php:1268 393 #: includes/class-emails-template.php:1301 394 #: includes/class-emails-template.php:1306 395 msgid "Traffic signals" 396 msgstr "" 397 398 #: includes/class-emails-template.php:1297 399 #: includes/class-emails-template.php:1375 400 #, php-format 401 msgid "Unusual traffic activity was detected for %s." 402 msgstr "" 403 404 #: includes/class-emails-template.php:1318 405 #, php-format 406 msgid "Manage Emails in WordPress: %s" 407 msgstr "" 408 409 #: includes/class-emails-template.php:1330 410 msgid "Manage Emails in WordPress" 411 msgstr "" 412 413 #: includes/class-emails-template.php:1340 414 #, php-format 415 msgid "Visit your site: %s" 416 msgstr "" 417 418 #: includes/class-emails-template.php:1351 419 msgid "your site" 420 msgstr "" 421 422 #: includes/class-emails-template.php:1353 423 #, php-format 424 msgid "Visit %s" 425 msgstr "" 426 427 #: includes/class-emails-template.php:1377 428 msgid "Unusual traffic activity was detected during this report period." 429 msgstr "" 430 431 #: includes/class-emails-template.php:1380 432 msgid "No unusual traffic activity was detected during this report period." 433 msgstr "" 434 435 #: includes/class-emails-template.php:1418 436 msgid "day" 437 msgstr "" 438 439 #: includes/class-emails-template.php:1421 440 msgid "month" 441 msgstr "" 442 443 #: includes/class-emails-template.php:1424 444 msgid "week" 445 msgstr "" 446 447 #: includes/class-emails-template.php:1469 includes/class-import.php:332 448 msgid "weekly" 449 msgstr "" 450 451 #: includes/class-emails-template.php:1484 452 msgid "Weekly Content Views Summary" 453 msgstr "" 454 455 #: includes/class-emails-template.php:1643 456 #, php-format 457 msgid "No previous %s comparison is available yet" 458 msgstr "" 459 460 #: includes/class-emails-template.php:1649 461 #, php-format 462 msgid "No change from the previous %s" 463 msgstr "" 464 465 #: includes/class-emails-template.php:1654 466 #, php-format 467 msgid "Up %1$s views from the previous %2$s" 468 msgstr "" 469 470 #: includes/class-emails-template.php:1656 471 #, php-format 472 msgid "Down %1$s views from the previous %2$s" 473 msgstr "" 474 475 #: includes/class-import.php:62 476 msgid "Custom Meta Key" 477 msgstr "" 478 479 #: includes/class-import.php:203 480 msgid "Override existing views" 481 msgstr "" 482 483 #: includes/class-import.php:204 484 msgid "Replace stored counts with the imported values." 485 msgstr "" 486 487 #: includes/class-import.php:208 488 msgid "Merge with existing views" 489 msgstr "" 490 491 #: includes/class-import.php:209 492 msgid "Add imported counts on top of the existing values." 493 msgstr "" 494 495 #: includes/class-import.php:213 496 msgid "Skip Existing" 497 msgstr "" 498 499 #: includes/class-import.php:214 500 msgid "Only import data when the target record does not exist yet." 501 msgstr "" 502 503 #: includes/class-import.php:218 504 msgid "Keep Higher Count" 505 msgstr "" 506 507 #: includes/class-import.php:219 508 msgid "" 509 "Keep whichever value is higher when comparing imported and stored counts." 510 msgstr "" 511 512 #: includes/class-import.php:223 513 msgid "Fill Empty Counts" 514 msgstr "" 515 516 #: includes/class-import.php:224 517 msgid "Only import data for posts or periods that currently store zero views." 518 msgstr "" 519 520 #: includes/class-import.php:323 2502 #: blocks/post-views/block.json 2503 #: src/blocks/post-views/block.json 2504 msgctxt "block description" 2505 msgid "Display post views for a given post." 2506 msgstr "" 2507 2508 #: blocks/post-views/block.json 2509 #: src/blocks/post-views/block.json 2510 msgctxt "block keyword" 2511 msgid "display" 2512 msgstr "" 2513 2514 #: blocks/pro-placeholder/most-viewed-terms/block.json 2515 msgctxt "block title" 2516 msgid "Most Viewed Terms" 2517 msgstr "" 2518 2519 #: blocks/pro-placeholder/most-viewed-terms/block.json 2520 msgctxt "block description" 2521 msgid "Displays a list of the most viewed terms. Requires Post Views Counter Pro." 2522 msgstr "" 2523 2524 #: blocks/pro-placeholder/most-viewed-terms/block.json 2525 #: blocks/pro-placeholder/term-views/block.json 2526 msgctxt "block keyword" 2527 msgid "taxonomy" 2528 msgstr "" 2529 2530 #: blocks/pro-placeholder/most-viewed-terms/block.json 2531 #: blocks/pro-placeholder/term-views/block.json 2532 msgctxt "block keyword" 2533 msgid "category" 2534 msgstr "" 2535 2536 #: blocks/pro-placeholder/most-viewed-terms/block.json 2537 #: blocks/pro-placeholder/term-views/block.json 2538 msgctxt "block keyword" 2539 msgid "tag" 2540 msgstr "" 2541 2542 #: blocks/pro-placeholder/most-viewed-terms/block.json 2543 #: blocks/pro-placeholder/most-viewed-users/block.json 2544 #: blocks/pro-placeholder/site-views/block.json 2545 #: blocks/pro-placeholder/term-views/block.json 2546 #: blocks/pro-placeholder/user-views/block.json 2547 msgctxt "block keyword" 2548 msgid "pro" 2549 msgstr "" 2550 2551 #: blocks/pro-placeholder/most-viewed-users/block.json 2552 msgctxt "block title" 2553 msgid "Most Viewed Authors" 2554 msgstr "" 2555 2556 #: blocks/pro-placeholder/most-viewed-users/block.json 2557 msgctxt "block description" 2558 msgid "Displays a list of the most viewed authors. Requires Post Views Counter Pro." 2559 msgstr "" 2560 2561 #: blocks/pro-placeholder/most-viewed-users/block.json 2562 #: blocks/pro-placeholder/user-views/block.json 2563 msgctxt "block keyword" 2564 msgid "author" 2565 msgstr "" 2566 2567 #: blocks/pro-placeholder/most-viewed-users/block.json 2568 #: blocks/pro-placeholder/user-views/block.json 2569 msgctxt "block keyword" 2570 msgid "user" 2571 msgstr "" 2572 2573 #: blocks/pro-placeholder/site-views/block.json 2574 msgctxt "block title" 2575 msgid "Site Views" 2576 msgstr "" 2577 2578 #: blocks/pro-placeholder/site-views/block.json 2579 msgctxt "block description" 2580 msgid "Display site views. Requires Post Views Counter Pro." 2581 msgstr "" 2582 2583 #: blocks/pro-placeholder/site-views/block.json 2584 msgctxt "block keyword" 2585 msgid "site" 2586 msgstr "" 2587 2588 #: blocks/pro-placeholder/site-views/block.json 2589 msgctxt "block keyword" 521 2590 msgid "total" 522 2591 msgstr "" 523 2592 524 #: includes/class-import.php:326 525 msgid "yearly" 526 msgstr "" 527 528 #: includes/class-import.php:329 529 msgid "monthly" 530 msgstr "" 531 532 #: includes/class-import.php:335 533 msgid "daily" 534 msgstr "" 535 536 #: includes/class-import.php:340 537 msgid "post types" 538 msgstr "" 539 540 #: includes/class-import.php:341 541 msgid "taxonomies" 542 msgstr "" 543 544 #: includes/class-import.php:342 545 msgid "author archives" 546 msgstr "" 547 548 #: includes/class-import.php:343 549 msgid "other pages" 550 msgstr "" 551 552 #: includes/class-import.php:344 553 msgid "traffic sources" 554 msgstr "" 555 556 #: includes/class-import.php:358 557 #, php-format 558 msgid "Imports %s view counts for %s" 559 msgstr "" 560 561 #: includes/class-import.php:360 562 #, php-format 563 msgid "Imports %s view counts" 564 msgstr "" 565 566 #: includes/class-import.php:372 567 #, php-format 568 msgid "PVC Pro additionally imports %s view counts" 569 msgstr "" 570 571 #: includes/class-import.php:394 572 msgid "and" 573 msgstr "" 574 575 #: includes/class-import.php:420 576 msgid "Invalid import provider selected." 577 msgstr "" 578 579 #: includes/class-import.php:561 580 msgid "" 581 "Enter the meta key from which the views data is to be retrieved during " 582 "import." 583 msgstr "" 584 585 #: includes/class-import.php:607 includes/class-import.php:732 586 #: includes/class-import.php:869 587 #, php-format 588 msgid "No valid views data found for %s." 589 msgstr "" 590 591 #: includes/class-import.php:607 592 #, php-format 593 msgid "meta key: %s" 594 msgstr "" 595 596 #: includes/class-import.php:621 includes/class-import.php:673 597 #, php-format 598 msgid "Meta key \"%s\"." 599 msgstr "" 600 601 #: includes/class-import.php:650 includes/class-import.php:772 602 #: includes/class-import.php:1125 includes/class-import.php:1393 603 msgid "No valid post data found to import." 604 msgstr "" 605 606 #: includes/class-import.php:973 607 #, php-format 608 msgid "Would skip %s non-post URLs." 609 msgstr "" 610 611 #: includes/class-import.php:1129 612 msgid "No post types are selected for tracking in settings." 613 msgstr "" 614 615 #: includes/class-import.php:1134 616 #, php-format 617 msgid "All %s URLs were skipped. Sample URLs: %s" 618 msgstr "" 619 620 #: includes/class-import.php:1181 621 #, php-format 622 msgid "Skipped %s non-post URLs." 623 msgstr "" 624 625 #: includes/class-import.php:1671 626 #, php-format 627 msgid "Analysis of %s:" 628 msgstr "" 629 630 #: includes/class-import.php:1673 631 #, php-format 632 msgid "Import from %s:" 633 msgstr "" 634 635 #: includes/class-import.php:1681 636 #, php-format 637 msgid "Found %s total views for %s posts." 638 msgstr "" 639 640 #: includes/class-import.php:1687 641 #, php-format 642 msgid "Successfully imported %s total views for %s posts." 643 msgstr "" 644 645 #: includes/class-import.php:1701 646 #, php-format 647 msgid "Skipped %1$s total views for %2$s posts." 648 msgstr "" 649 650 #: includes/class-integrations.php:110 651 msgid "" 652 "Integrate with WordPress block editor to order posts by views in Query Loop " 653 "and Latest Posts blocks." 654 msgstr "" 655 656 #: includes/class-integrations.php:117 657 msgid "Query Loop Block" 658 msgstr "" 659 660 #: includes/class-integrations.php:118 661 msgid "Enables ordering posts by view count in the core Query Loop block." 662 msgstr "" 663 664 #: includes/class-integrations.php:122 665 msgid "Latest Posts Block" 666 msgstr "" 667 668 #: includes/class-integrations.php:123 669 msgid "Enables ordering posts by view count in the core Latest Posts block." 670 msgstr "" 671 672 #: includes/class-integrations.php:130 673 msgid "Integrate with AMP plugin to handle post views on AMP pages." 674 msgstr "" 675 676 #: includes/class-integrations.php:137 677 msgid "AMP Support" 678 msgstr "" 679 680 #: includes/class-integrations.php:138 681 msgid "Tracks and displays views on AMP-enabled pages." 682 msgstr "" 683 684 #: includes/class-integrations.php:145 685 msgid "Integrate with Beaver Builder to order module posts by views." 686 msgstr "" 687 688 #: includes/class-integrations.php:152 689 msgid "Post Grid Module" 690 msgstr "" 691 692 #: includes/class-integrations.php:153 693 msgid "Orders posts by views in the Beaver Builder Post Grid module." 694 msgstr "" 695 696 #: includes/class-integrations.php:157 697 msgid "Post Carousel Module" 698 msgstr "" 699 700 #: includes/class-integrations.php:158 701 msgid "Orders posts by views in the Beaver Builder Post Carousel module." 702 msgstr "" 703 704 #: includes/class-integrations.php:162 includes/class-integrations.php:202 705 msgid "Post Slider Module" 706 msgstr "" 707 708 #: includes/class-integrations.php:163 709 msgid "Orders posts by views in the Beaver Builder Post Slider module." 710 msgstr "" 711 712 #: includes/class-integrations.php:170 713 msgid "Integrate with CoBlocks to order post feed results by views." 714 msgstr "" 715 716 #: includes/class-integrations.php:177 includes/class-integrations.php:282 717 msgid "Posts Block" 718 msgstr "" 719 720 #: includes/class-integrations.php:178 721 msgid "Adds post views ordering to the CoBlocks Posts block." 722 msgstr "" 723 724 #: includes/class-integrations.php:182 725 msgid "Post Carousel Block" 726 msgstr "" 727 728 #: includes/class-integrations.php:183 729 msgid "Adds post views ordering to the CoBlocks Post Carousel block." 730 msgstr "" 731 732 #: includes/class-integrations.php:190 733 msgid "" 734 "Integrate with Divi Theme to order module posts by views when the module " 735 "uses the \"orderby-post-views\" CSS class." 736 msgstr "" 737 738 #: includes/class-integrations.php:197 739 msgid "Blog Module" 740 msgstr "" 741 742 #: includes/class-integrations.php:198 743 msgid "Orders posts by views in the Divi Blog module." 744 msgstr "" 745 746 #: includes/class-integrations.php:203 747 msgid "Orders posts by views in the Divi Post Slider module." 748 msgstr "" 749 750 #: includes/class-integrations.php:207 751 msgid "Portfolio Module" 752 msgstr "" 753 754 #: includes/class-integrations.php:208 755 msgid "Orders posts by views in the Divi Portfolio module." 756 msgstr "" 757 758 #: includes/class-integrations.php:215 759 msgid "" 760 "Integrate with Elementor Pro to order posts by views when a widget query " 761 "uses the \"post_views\" Query ID." 762 msgstr "" 763 764 #: includes/class-integrations.php:222 765 msgid "Posts Widget" 766 msgstr "" 767 768 #: includes/class-integrations.php:223 769 msgid "" 770 "Orders posts by views in the Elementor Pro Posts widget when its Query ID is " 771 "set to \"post_views\"." 772 msgstr "" 773 774 #: includes/class-integrations.php:227 775 msgid "Portfolio Widget" 776 msgstr "" 777 778 #: includes/class-integrations.php:228 779 msgid "" 780 "Orders items by views in the Elementor Pro Portfolio widget when its Query " 781 "ID is set to \"post_views\"." 782 msgstr "" 783 784 #: includes/class-integrations.php:232 785 msgid "Loop Grid / Loop Carousel" 786 msgstr "" 787 788 #: includes/class-integrations.php:233 789 msgid "" 790 "Orders items by views in the Elementor Pro Loop Grid and Loop Carousel " 791 "widgets when the Query ID is set to \"post_views\"." 792 msgstr "" 793 794 #: includes/class-integrations.php:240 795 msgid "Integrate with GenerateBlocks to order Query block results by views." 796 msgstr "" 797 798 #: includes/class-integrations.php:247 799 msgid "Dynamic Content" 800 msgstr "" 801 802 #: includes/class-integrations.php:248 803 msgid "Adds post_views ordering to the GenerateBlocks Query block." 804 msgstr "" 805 806 #: includes/class-integrations.php:255 807 msgid "" 808 "Integrate with JetEngine plugin to display post views in custom listings and " 809 "queries." 810 msgstr "" 811 812 #: includes/class-integrations.php:262 813 msgid "Query Builder" 814 msgstr "" 815 816 #: includes/class-integrations.php:263 817 msgid "Enables ordering posts by view count in Query Builder posts queries." 818 msgstr "" 819 820 #: includes/class-integrations.php:267 821 msgid "Listing Grid" 822 msgstr "" 823 824 #: includes/class-integrations.php:268 825 msgid "" 826 "Enables ordering posts by view count in Listing Grid, Maps Listing and " 827 "Calendar widgets." 828 msgstr "" 829 830 #: includes/class-integrations.php:275 831 msgid "" 832 "Integrate with Kadence Blocks to order post results by views in the Posts " 833 "block." 834 msgstr "" 835 836 #: includes/class-integrations.php:283 837 msgid "Adds post views ordering to the Posts block." 838 msgstr "" 839 840 #: includes/class-integrations.php:290 841 msgid "" 842 "Integrate with Polylang to filter reports, exports, and dashboard widgets by " 843 "language." 844 msgstr "" 845 846 #: includes/class-integrations.php:297 includes/class-integrations.php:317 847 msgid "Reports Language Filters" 848 msgstr "" 849 850 #: includes/class-integrations.php:298 includes/class-integrations.php:318 851 msgid "" 852 "Adds language filtering and a language column to Reports tables, charts, and " 853 "exports." 854 msgstr "" 855 856 #: includes/class-integrations.php:302 includes/class-integrations.php:322 857 msgid "Dashboard Widgets" 858 msgstr "" 859 860 #: includes/class-integrations.php:303 includes/class-integrations.php:323 861 msgid "" 862 "Filters dashboard widgets (site, post, and term views) by the selected " 863 "language." 864 msgstr "" 865 866 #: includes/class-integrations.php:310 867 msgid "" 868 "Integrate with WPML to filter reports, exports, and dashboard widgets by " 869 "language." 870 msgstr "" 871 872 #: includes/class-settings-api.php:448 873 msgid "Reset to defaults" 874 msgstr "" 875 876 #: includes/class-settings-api.php:878 877 msgid "Open color picker" 878 msgstr "" 879 880 #: includes/class-settings-api.php:1129 881 msgid "Settings saved." 882 msgstr "" 883 884 #: includes/class-settings-api.php:1159 885 msgid "Settings restored to defaults." 886 msgstr "" 887 888 #: includes/class-settings-display.php:41 889 msgid "Counter Appearance" 890 msgstr "" 891 892 #: includes/class-settings-display.php:46 893 msgid "Display Targets" 894 msgstr "" 895 896 #: includes/class-settings-display.php:51 897 msgid "Display Audience" 898 msgstr "" 899 900 #: includes/class-settings-display.php:56 901 msgid "Admin Interface" 902 msgstr "" 903 904 #: includes/class-settings-display.php:73 905 #: includes/class-settings-general.php:113 906 msgid "logged in users" 907 msgstr "" 908 909 #: includes/class-settings-display.php:74 910 #: includes/class-settings-general.php:114 911 msgid "guests" 912 msgstr "" 913 914 #: includes/class-settings-display.php:75 915 #: includes/class-settings-general.php:115 916 msgid "selected user roles" 917 msgstr "" 918 919 #: includes/class-settings-display.php:84 920 msgid "Views Label" 921 msgstr "" 922 923 #: includes/class-settings-display.php:88 924 msgid "Text shown next to the view count." 925 msgstr "" 926 927 #: includes/class-settings-display.php:95 includes/class-widgets.php:171 928 msgid "Views Period" 929 msgstr "" 930 931 #: includes/class-settings-display.php:101 932 msgid "Time range used when displaying the number of views." 933 msgstr "" 934 935 #: includes/class-settings-display.php:109 includes/class-widgets.php:207 936 msgid "Display Style" 937 msgstr "" 938 939 #: includes/class-settings-display.php:113 940 msgid "Choose whether to show an icon, label text, or both." 941 msgstr "" 942 943 #: includes/class-settings-display.php:117 944 msgid "Icon" 945 msgstr "" 946 947 #: includes/class-settings-display.php:118 948 msgid "Label" 949 msgstr "" 950 951 #: includes/class-settings-display.php:123 952 msgid "Icon Class" 953 msgstr "" 954 955 #: includes/class-settings-display.php:135 956 msgid "" 957 "Enter the CSS class for the views icon. Any Dashicons class is supported." 958 msgstr "" 959 960 #: includes/class-settings-display.php:140 961 msgid "Position" 962 msgstr "" 963 964 #: includes/class-settings-display.php:144 965 #, php-format 966 msgid "" 967 "Where to insert the counter automatically. Use %s shortcode for manual " 968 "placement." 969 msgstr "" 970 971 #: includes/class-settings-display.php:146 972 msgid "Before the content" 973 msgstr "" 974 975 #: includes/class-settings-display.php:147 976 msgid "After the content" 977 msgstr "" 978 979 #: includes/class-settings-display.php:148 980 msgid "Manual only" 981 msgstr "" 982 983 #: includes/class-settings-display.php:153 984 msgid "Admin Column" 985 msgstr "" 986 987 #: includes/class-settings-display.php:157 988 msgid "Show a \"Views\" column on post and page list screens." 989 msgstr "" 990 991 #: includes/class-settings-display.php:161 992 msgid "Admin Edit" 993 msgstr "" 994 995 #: includes/class-settings-display.php:165 996 msgid "Allow editing the view count on the post edit screen." 997 msgstr "" 998 999 #: includes/class-settings-display.php:169 1000 msgid "Dynamic Loading" 1001 msgstr "" 1002 1003 #: includes/class-settings-display.php:176 1004 msgid "Load the view count dynamically to avoid caching the displayed value." 1005 msgstr "" 1006 1007 #: includes/class-settings-display.php:181 1008 msgid "Format Number" 1009 msgstr "" 1010 1011 #: includes/class-settings-display.php:184 1012 msgid "" 1013 "Format the view count according to the site locale (uses the WordPress " 1014 "number_format_i18n function)." 1015 msgstr "" 1016 1017 #: includes/class-settings-display.php:188 1018 #: includes/class-settings-general.php:135 1019 msgid "Taxonomies" 1020 msgstr "" 1021 1022 #: includes/class-settings-display.php:195 1023 msgid "" 1024 "Display the view count on category, tag, or custom taxonomy archive pages." 1025 msgstr "" 1026 1027 #: includes/class-settings-display.php:203 1028 msgid "Select taxonomies where the view counter will be displayed." 1029 msgstr "" 1030 1031 #: includes/class-settings-display.php:218 1032 #: includes/class-settings-general.php:147 1033 msgid "Author Archives" 1034 msgstr "" 1035 1036 #: includes/class-settings-display.php:225 1037 msgid "Display the view count on author archive pages." 1038 msgstr "" 1039 1040 #: includes/class-settings-display.php:230 1041 #: includes/class-settings-general.php:127 includes/class-widgets.php:160 1042 msgid "Post Types" 1043 msgstr "" 1044 1045 #: includes/class-settings-display.php:233 1046 msgid "Select post types where the view counter will be displayed." 1047 msgstr "" 1048 1049 #: includes/class-settings-display.php:238 1050 msgid "Page Type" 1051 msgstr "" 1052 1053 #: includes/class-settings-display.php:241 1054 msgid "Select page contexts where the view counter will be displayed." 1055 msgstr "" 1056 1057 #: includes/class-settings-display.php:245 1058 msgid "Home" 1059 msgstr "" 1060 1061 #: includes/class-settings-display.php:246 1062 msgid "Archives" 1063 msgstr "" 1064 1065 #: includes/class-settings-display.php:247 1066 msgid "Single posts and pages" 1067 msgstr "" 1068 1069 #: includes/class-settings-display.php:248 1070 msgid "Search results" 1071 msgstr "" 1072 1073 #: includes/class-settings-display.php:254 1074 msgid "User Type" 1075 msgstr "" 1076 1077 #: includes/class-settings-display.php:257 1078 msgid "Hide the view counter for selected visitor groups." 1079 msgstr "" 1080 1081 #: includes/class-settings-display.php:265 1082 msgid "User Roles" 1083 msgstr "" 1084 1085 #: includes/class-settings-display.php:268 1086 msgid "Hide the view counter for selected user roles." 1087 msgstr "" 1088 1089 #: includes/class-settings-display.php:278 1090 msgid "Toolbar Chart" 1091 msgstr "" 1092 1093 #: includes/class-settings-display.php:281 1094 msgid "A views chart is shown for content types that are being counted." 1095 msgstr "" 1096 1097 #: includes/class-settings-display.php:282 1098 msgid "Show a views chart in the admin toolbar." 1099 msgstr "" 1100 1101 #: includes/class-settings-display.php:286 1102 msgid "Menu Position" 1103 msgstr "" 1104 1105 #: includes/class-settings-display.php:289 1106 msgid "Top menu" 1107 msgstr "" 1108 1109 #: includes/class-settings-display.php:290 1110 msgid "Settings submenu" 1111 msgstr "" 1112 1113 #: includes/class-settings-display.php:292 1114 msgid "Choose where the plugin menu appears in the admin sidebar." 1115 msgstr "" 1116 1117 #: includes/class-settings-display.php:434 1118 msgid "" 1119 "Choose where the counter is inserted and which content types it attaches to." 1120 msgstr "" 1121 1122 #: includes/class-settings-display.php:443 1123 msgid "" 1124 "Control which visitor groups can see the counter. These rules apply on top " 1125 "of the display targets." 1126 msgstr "" 1127 1128 #: includes/class-settings-display.php:452 1129 msgid "" 1130 "Adjust the label, period, icon, and formatting used when the counter is " 1131 "rendered." 1132 msgstr "" 1133 1134 #: includes/class-settings-display.php:461 1135 msgid "" 1136 "Control how view counts are shown and managed in WordPress admin (columns, " 1137 "edit permissions, toolbar chart)." 1138 msgstr "" 1139 1140 #: includes/class-settings-emails.php:37 1141 msgid "Email Summaries" 1142 msgstr "" 1143 1144 #: includes/class-settings-emails.php:42 1145 msgid "Email Recipients" 1146 msgstr "" 1147 1148 #: includes/class-settings-emails.php:47 1149 msgid "Email Template" 1150 msgstr "" 1151 1152 #: includes/class-settings-emails.php:52 1153 msgid "Test Email" 1154 msgstr "" 1155 1156 #: includes/class-settings-emails.php:57 1157 msgid "Delivery & Status" 1158 msgstr "" 1159 1160 #: includes/class-settings-emails.php:73 1161 msgid "Email Summary" 1162 msgstr "" 1163 1164 #: includes/class-settings-emails.php:76 1165 msgid "Send a summary of tracked content views to the selected recipient." 1166 msgstr "" 1167 1168 #: includes/class-settings-emails.php:80 1169 msgid "Summary Frequency" 1170 msgstr "" 1171 1172 #: includes/class-settings-emails.php:89 1173 msgid "Daily" 1174 msgstr "" 1175 1176 #: includes/class-settings-emails.php:90 1177 msgid "Weekly" 1178 msgstr "" 1179 1180 #: includes/class-settings-emails.php:91 1181 msgid "Monthly" 1182 msgstr "" 1183 1184 #: includes/class-settings-emails.php:93 1185 msgid "Choose how often views tracking summaries are sent." 1186 msgstr "" 1187 1188 #: includes/class-settings-emails.php:98 1189 msgid "Minimum Tracked Views" 1190 msgstr "" 1191 1192 #: includes/class-settings-emails.php:103 1193 msgid "" 1194 "Do not send the summary if the report period has fewer than this many " 1195 "tracked views." 1196 msgstr "" 1197 1198 #: includes/class-settings-emails.php:109 1199 msgid "Top Content Items" 1200 msgstr "" 1201 1202 #: includes/class-settings-emails.php:114 1203 msgid "Choose how many top content items are included in each summary." 1204 msgstr "" 1205 1206 #: includes/class-settings-emails.php:119 1207 msgid "Top Gainers and Decliners" 1208 msgstr "" 1209 1210 #: includes/class-settings-emails.php:127 1211 msgid "" 1212 "Show which content is gaining or losing momentum compared with previous " 1213 "periods." 1214 msgstr "" 1215 1216 #: includes/class-settings-emails.php:128 1217 #, php-format 1218 msgid "" 1219 "When matching data is available, this appears in the Traffic signals section " 1220 "if the email template includes %%traffic_signals%%." 1221 msgstr "" 1222 1223 #: includes/class-settings-emails.php:132 1224 msgid "Author Summary" 1225 msgstr "" 1226 1227 #: includes/class-settings-emails.php:140 1228 msgid "" 1229 "Include the authors whose content received the most tracked views during the " 1230 "report period." 1231 msgstr "" 1232 1233 #: includes/class-settings-emails.php:141 1234 #, php-format 1235 msgid "" 1236 "When matching data is available, this appears in the Report summary section " 1237 "if the email template includes %%report_summary%%." 1238 msgstr "" 1239 1240 #: includes/class-settings-emails.php:145 1241 msgid "Source Summary" 1242 msgstr "" 1243 1244 #: includes/class-settings-emails.php:153 1245 msgid "" 1246 "Include top referrers or source dimensions when source tracking is available." 1247 msgstr "" 1248 1249 #: includes/class-settings-emails.php:154 1250 #, php-format 1251 msgid "" 1252 "When source tracking data is available, this appears in the Report summary " 1253 "section if the email template includes %%report_summary%%." 1254 msgstr "" 1255 1256 #: includes/class-settings-emails.php:159 1257 msgid "Recipient Email" 1258 msgstr "" 1259 1260 #: includes/class-settings-emails.php:163 1261 msgid "" 1262 "The email address that receives summary emails. Defaults to the site " 1263 "administrator email." 1264 msgstr "" 1265 1266 #: includes/class-settings-emails.php:168 1267 msgid "Additional Recipients" 1268 msgstr "" 1269 1270 #: includes/class-settings-emails.php:176 1271 msgid "Send summaries to multiple people with CC and BCC recipients." 1272 msgstr "" 1273 1274 #: includes/class-settings-emails.php:180 1275 msgid "CC Recipients" 1276 msgstr "" 1277 1278 #: includes/class-settings-emails.php:195 1279 msgid "Send visible copies to additional recipients." 1280 msgstr "" 1281 1282 #: includes/class-settings-emails.php:199 1283 msgid "BCC Recipients" 1284 msgstr "" 1285 1286 #: includes/class-settings-emails.php:214 1287 msgid "Send private copies to additional recipients." 1288 msgstr "" 1289 1290 #: includes/class-settings-emails.php:219 1291 msgid "Email Subject" 1292 msgstr "" 1293 1294 #: includes/class-settings-emails.php:229 1295 msgid "Email Content" 1296 msgstr "" 1297 1298 #: includes/class-settings-emails.php:239 1299 msgid "Send Test To" 1300 msgstr "" 1301 1302 #: includes/class-settings-emails.php:247 1303 msgid "Schedule Status" 1304 msgstr "" 1305 1306 #: includes/class-settings-emails.php:250 1307 msgid "" 1308 "Weekly summaries are scheduled for Monday after the previous full week has " 1309 "ended." 1310 msgstr "" 1311 1312 #: includes/class-settings-emails.php:251 1313 msgid "" 1314 "Summary emails are scheduled with WordPress cron. Delivery time may vary " 1315 "depending on site traffic and hosting configuration." 1316 msgstr "" 1317 1318 #: includes/class-settings-emails.php:256 1319 msgid "Next Scheduled Email" 1320 msgstr "" 1321 1322 #: includes/class-settings-emails.php:264 1323 msgid "Last Sent" 1324 msgstr "" 1325 1326 #: includes/class-settings-emails.php:272 1327 msgid "Last Error" 1328 msgstr "" 1329 1330 #: includes/class-settings-emails.php:287 1331 msgid "Send email summaries with your most viewed content and view totals." 1332 msgstr "" 1333 1334 #: includes/class-settings-emails.php:296 1335 msgid "Choose who should receive your email summaries." 1336 msgstr "" 1337 1338 #: includes/class-settings-emails.php:305 1339 msgid "Review scheduling, delivery, and recent email status information." 1340 msgstr "" 1341 1342 #: includes/class-settings-emails.php:314 1343 msgid "Customize the subject and message used for content views summaries." 1344 msgstr "" 1345 1346 #: includes/class-settings-emails.php:324 1347 msgid "" 1348 "Send a test using the latest available summary. This does not change the " 1349 "saved recipient or scheduled delivery." 1350 msgstr "" 1351 1352 #: includes/class-settings-emails.php:337 1353 msgid "email@example.com" 1354 msgstr "" 1355 1356 #: includes/class-settings-emails.php:337 1357 msgid "Test email recipient" 1358 msgstr "" 1359 1360 #: includes/class-settings-emails.php:338 1361 msgid "Send Test Email" 1362 msgstr "" 1363 1364 #: includes/class-settings-emails.php:338 1365 msgid "Sending..." 1366 msgstr "" 1367 1368 #: includes/class-settings-emails.php:356 1369 msgid "Sorry, you are not allowed to do that." 1370 msgstr "" 1371 1372 #: includes/class-settings-emails.php:395 1373 #: includes/class-settings-emails.php:494 1374 msgid "Enter a valid test recipient email address." 1375 msgstr "" 1376 1377 #: includes/class-settings-emails.php:417 1378 msgid "" 1379 "There is not enough tracked data from the latest complete week to send a " 1380 "real test summary yet." 1381 msgstr "" 1382 1383 #: includes/class-settings-emails.php:437 1384 msgid "The summary test email was sent successfully." 1385 msgstr "" 1386 1387 #: includes/class-settings-emails.php:445 1388 #, php-format 1389 msgid "The test email could not be sent. %s" 1390 msgstr "" 1391 1392 #: includes/class-settings-emails.php:446 1393 msgid "" 1394 "The test email could not be sent. Check your WordPress mail configuration " 1395 "and try again." 1396 msgstr "" 1397 1398 #: includes/class-settings-emails.php:463 1399 msgid "Enter a valid recipient email address for the views summary email." 1400 msgstr "" 1401 1402 #: includes/class-settings-emails.php:469 1403 msgid "Recipient email is required while the views summary email is enabled." 1404 msgstr "" 1405 1406 #: includes/class-settings-emails.php:559 1407 msgid "Minimum tracked views cannot be lower than 0." 1408 msgstr "" 1409 1410 #: includes/class-settings-emails.php:588 1411 #, php-format 1412 msgid "" 1413 "%1$s contained tags that are not available in this field. Removed tags: " 1414 "%2$s. Supported tags here: %3$s" 1415 msgstr "" 1416 1417 #: includes/class-settings-emails.php:711 1418 msgid "Customize the subject line for summary emails." 1419 msgstr "" 1420 1421 #: includes/class-settings-emails.php:713 1422 #, php-format 1423 msgid "Use supported subject tags such as %1$s and %2$s." 1424 msgstr "" 1425 1426 #: includes/class-settings-emails.php:727 1427 msgid "Customize the main message sent with each email summary." 1428 msgstr "" 1429 1430 #: includes/class-settings-emails.php:729 1431 #, php-format 1432 msgid "Use supported content tags such as %s." 1433 msgstr "" 1434 1435 #: includes/class-settings-emails.php:814 1436 msgid "Not sent yet." 1437 msgstr "" 1438 1439 #: includes/class-settings-emails.php:831 1440 msgid "Not scheduled." 1441 msgstr "" 1442 1443 #: includes/class-settings-emails.php:844 1444 msgid "No email errors recorded yet." 1445 msgstr "" 1446 1447 #: includes/class-settings-general.php:54 1448 msgid "PHP" 1449 msgstr "" 1450 1451 #: includes/class-settings-general.php:55 1452 msgid "JavaScript" 1453 msgstr "" 1454 1455 #: includes/class-settings-general.php:56 1456 msgid "REST API" 1457 msgstr "" 1458 1459 #: includes/class-settings-general.php:57 1460 msgid "Fast AJAX" 1461 msgstr "" 1462 1463 #: includes/class-settings-general.php:72 1464 msgid "Tracking Targets" 1465 msgstr "" 1466 1467 #: includes/class-settings-general.php:77 1468 msgid "Tracking Behavior" 1469 msgstr "" 1470 1471 #: includes/class-settings-general.php:82 1472 msgid "Visitor Exclusions" 1473 msgstr "" 1474 1475 #: includes/class-settings-general.php:87 1476 msgid "Performance & Caching" 1477 msgstr "" 1478 1479 #: includes/class-settings-general.php:101 1480 #: includes/class-settings-general.php:452 1481 msgid "minutes" 1482 msgstr "" 1483 1484 #: includes/class-settings-general.php:102 1485 #: includes/class-settings-general.php:217 1486 msgid "hours" 1487 msgstr "" 1488 1489 #: includes/class-settings-general.php:103 1490 msgid "days" 1491 msgstr "" 1492 1493 #: includes/class-settings-general.php:104 1494 msgid "weeks" 1495 msgstr "" 1496 1497 #: includes/class-settings-general.php:105 1498 msgid "months" 1499 msgstr "" 1500 1501 #: includes/class-settings-general.php:106 1502 msgid "years" 1503 msgstr "" 1504 1505 #: includes/class-settings-general.php:111 1506 msgid "crawlers" 1507 msgstr "" 1508 1509 #: includes/class-settings-general.php:112 1510 msgid "AI bots" 1511 msgstr "" 1512 1513 #: includes/class-settings-general.php:130 1514 msgid "Select post types whose views should be counted." 1515 msgstr "" 1516 1517 #: includes/class-settings-general.php:138 1518 msgid "Enable counting views on taxonomy term archive pages." 1519 msgstr "" 1520 1521 #: includes/class-settings-general.php:150 1522 msgid "Enable counting views on author archive pages." 1523 msgstr "" 1524 1525 #: includes/class-settings-general.php:159 1526 msgid "Other Pages" 1527 msgstr "" 1528 1529 #: includes/class-settings-general.php:162 1530 msgid "" 1531 "Track views on the front page, post type archives, date archives, search " 1532 "results, 404 pages, and WordPress authentication pages such as login, " 1533 "registration, and password reset." 1534 msgstr "" 1535 1536 #: includes/class-settings-general.php:171 1537 msgid "Traffic Sources" 1538 msgstr "" 1539 1540 #: includes/class-settings-general.php:174 1541 msgid "" 1542 "Collect aggregate stats about visitors' browsers, devices, operating systems " 1543 "and referrers." 1544 msgstr "" 1545 1546 #: includes/class-settings-general.php:183 1547 msgid "Counter Mode" 1548 msgstr "" 1549 1550 #: includes/class-settings-general.php:186 1551 msgid "" 1552 "Choose how views are recorded. If you use caching, select JavaScript, REST " 1553 "API or Fast AJAX (up to <code>10+</code> times faster)." 1554 msgstr "" 1555 1556 #: includes/class-settings-general.php:194 1557 msgid "Data Storage" 1558 msgstr "" 1559 1560 #: includes/class-settings-general.php:199 1561 msgid "" 1562 "Choose how to store the content views data in the user's browser - with or " 1563 "without cookies." 1564 msgstr "" 1565 1566 #: includes/class-settings-general.php:202 1567 msgid "Cookies" 1568 msgstr "" 1569 1570 #: includes/class-settings-general.php:203 1571 msgid "Cookieless" 1572 msgstr "" 1573 1574 #: includes/class-settings-general.php:210 1575 msgid "Count Interval" 1576 msgstr "" 1577 1578 #: includes/class-settings-general.php:223 1579 msgid "Count Time" 1580 msgstr "" 1581 1582 #: includes/class-settings-general.php:229 1583 msgid "" 1584 "Whether to store the views using GMT timezone or adjust it to the GMT offset " 1585 "of the site." 1586 msgstr "" 1587 1588 #: includes/class-settings-general.php:231 1589 msgid "GMT Time" 1590 msgstr "" 1591 1592 #: includes/class-settings-general.php:232 1593 msgid "Local Time" 1594 msgstr "" 1595 1596 #: includes/class-settings-general.php:238 1597 msgid "Strict Counts" 1598 msgstr "" 1599 1600 #: includes/class-settings-general.php:246 1601 msgid "" 1602 "Prevent bypassing the count interval (for example by using incognito mode or " 1603 "clearing cookies)." 1604 msgstr "" 1605 1606 #: includes/class-settings-general.php:251 1607 msgid "Cleanup Interval" 1608 msgstr "" 1609 1610 #: includes/class-settings-general.php:254 1611 #, php-format 1612 msgid "" 1613 "Delete daily content view data older than the period specified above. Enter " 1614 "%s to keep data regardless of age. Cleanup runs once per day." 1615 msgstr "" 1616 1617 #: includes/class-settings-general.php:263 1618 msgid "Caching Compatibility" 1619 msgstr "" 1620 1621 #: includes/class-settings-general.php:278 1622 msgid "Object Cache Support" 1623 msgstr "" 1624 1625 #: includes/class-settings-general.php:293 1626 msgid "Exclude Visitors" 1627 msgstr "" 1628 1629 #: includes/class-settings-general.php:296 1630 msgid "Use this to exclude specific visitor groups from counting views." 1631 msgstr "" 1632 1633 #: includes/class-settings-general.php:307 1634 msgid "Exclude User Roles" 1635 msgstr "" 1636 1637 #: includes/class-settings-general.php:310 1638 msgid "Use this to exclude specific user roles from counting views." 1639 msgstr "" 1640 1641 #: includes/class-settings-general.php:326 1642 msgid "Exclude IPs" 1643 msgstr "" 1644 1645 #: includes/class-settings-general.php:375 1646 msgid "" 1647 "Minimum time between counting new views from the same visitor, in hours. " 1648 "Enter <code>0</code> to count every page view." 1649 msgstr "" 1650 1651 #: includes/class-settings-general.php:453 1652 msgid "Persistent Object Cache" 1653 msgstr "" 1654 1655 #: includes/class-settings-general.php:453 1656 msgid "available" 1657 msgstr "" 1658 1659 #: includes/class-settings-general.php:453 1660 msgid "unavailable" 1661 msgstr "" 1662 1663 #: includes/class-settings-general.php:454 1664 #, php-format 1665 msgid "" 1666 "How often to flush cached view counts from the object cache into the " 1667 "database. This feature is used only if a persistent object cache like %s or " 1668 "%s is detected and the interval is greater than %s. When used, view counts " 1669 "will be collected and stored in the object cache instead of the database and " 1670 "will then be asynchronously flushed to the database according to the " 1671 "specified interval. The maximum value is %s which means 24 hours.%sNotice:%s " 1672 "Potential data loss may occur if the object cache is cleared/unavailable for " 1673 "the duration of the interval." 1674 msgstr "" 1675 1676 #: includes/class-settings-general.php:533 1677 #: includes/class-settings-general.php:539 1678 msgid "Remove" 1679 msgstr "" 1680 1681 #: includes/class-settings-general.php:547 1682 msgid "Add new" 1683 msgstr "" 1684 1685 #: includes/class-settings-general.php:547 1686 msgid "Add my current IP" 1687 msgstr "" 1688 1689 #: includes/class-settings-general.php:550 1690 msgid "" 1691 "Add IPv4 or IPv6 addresses to exclude them from counting views. Wildcards " 1692 "are supported for IPv4 only (e.g. 192.168.0.*)." 1693 msgstr "" 1694 1695 #: includes/class-settings-general.php:589 1696 msgid "" 1697 "Control which post types, archives and other content types are included in " 1698 "view counting." 1699 msgstr "" 1700 1701 #: includes/class-settings-general.php:598 1702 msgid "" 1703 "Control how views are recorded — counting mode, intervals, time zone, and " 1704 "cleanup." 1705 msgstr "" 1706 1707 #: includes/class-settings-general.php:607 1708 msgid "" 1709 "Exclude specific visitor groups or IP addresses from incrementing view " 1710 "counts." 1711 msgstr "" 1712 1713 #: includes/class-settings-general.php:616 1714 msgid "Configure caching compatibility and object-cache handling for counting." 1715 msgstr "" 1716 1717 #: includes/class-settings-general.php:631 1718 msgid "Currently detected active caching plugins" 1719 msgstr "" 1720 1721 #: includes/class-settings-general.php:639 1722 msgid "No compatible caching plugins found." 1723 msgstr "" 1724 1725 #: includes/class-settings-general.php:651 1726 msgid "Enable compatibility tweaks for supported caching plugins." 1727 msgstr "" 1728 1729 #: includes/class-settings-general.php:655 1730 #: includes/class-settings-general.php:671 1731 #: includes/class-settings-integrations.php:97 1732 msgid "(available)" 1733 msgstr "" 1734 1735 #: includes/class-settings-general.php:667 1736 msgid "Enable Redis or Memcached object cache optimization." 1737 msgstr "" 1738 1739 #: includes/class-settings-general.php:704 1740 msgid "Persistent object cache has been detected." 1741 msgstr "" 1742 1743 #: includes/class-settings-general.php:707 1744 #, php-format 1745 msgid "" 1746 "This feature requires a persistent object cache like %s or %s to be " 1747 "installed and activated." 1748 msgstr "" 1749 1750 #: includes/class-settings-integrations.php:22 includes/class-settings.php:653 1751 #: includes/class-settings.php:721 includes/class-settings.php:722 1752 msgid "Integrations" 1753 msgstr "" 1754 1755 #: includes/class-settings-integrations.php:65 1756 msgid "Manage available Post Views Counter integrations." 1757 msgstr "" 1758 1759 #: includes/class-settings-other.php:36 1760 msgid "Plugin Status" 1761 msgstr "" 1762 1763 #: includes/class-settings-other.php:41 1764 msgid "Data Import" 1765 msgstr "" 1766 1767 #: includes/class-settings-other.php:46 1768 msgid "Data Removal" 1769 msgstr "" 1770 1771 #: includes/class-settings-other.php:61 1772 msgid "License Key" 1773 msgstr "" 1774 1775 #: includes/class-settings-other.php:66 1776 #, php-format 1777 msgid "" 1778 "Enter your %s license key (requires Pro version to be installed and active)." 1779 msgstr "" 1780 1781 #: includes/class-settings-other.php:73 1782 msgid "Import From" 1783 msgstr "" 1784 1785 #: includes/class-settings-other.php:81 1786 msgid "Import Strategy" 1787 msgstr "" 1788 1789 #: includes/class-settings-other.php:93 1790 msgid "" 1791 "Click Analyse Views to check how many views are available for import, or " 1792 "Import Views to begin the import process." 1793 msgstr "" 1794 1795 #: includes/class-settings-other.php:99 includes/class-settings-other.php:274 1796 msgid "Delete Views" 1797 msgstr "" 1798 1799 #: includes/class-settings-other.php:102 1800 msgid "" 1801 "Delete ALL the existing post views data. Note that this is an irreversible " 1802 "process!" 1803 msgstr "" 1804 1805 #: includes/class-settings-other.php:108 1806 msgid "Delete on Deactivation" 1807 msgstr "" 1808 1809 #: includes/class-settings-other.php:111 1810 msgid "" 1811 "When enabled, deactivating the plugin will delete all plugin data from the " 1812 "database, including all content view counts." 1813 msgstr "" 1814 1815 #: includes/class-settings-other.php:112 1816 msgid "Delete all plugin data on deactivation." 1817 msgstr "" 1818 1819 #: includes/class-settings-other.php:157 1820 #, php-format 1821 msgid "" 1822 "%s is not currently available. Please install and activate the required " 1823 "plugin." 1824 msgstr "" 1825 1826 #: includes/class-settings-other.php:167 1827 msgid "Choose a data source to import existing view counts from." 1828 msgstr "" 1829 1830 #: includes/class-settings-other.php:179 1831 #, php-format 1832 msgid "" 1833 "%s is not available. Please install and activate the required plugin to use " 1834 "this import source." 1835 msgstr "" 1836 1837 #: includes/class-settings-other.php:236 1838 msgid "Choose how to handle existing view counts when importing." 1839 msgstr "" 1840 1841 #: includes/class-settings-other.php:261 1842 msgid "Analyse Views" 1843 msgstr "" 1844 1845 #: includes/class-settings-other.php:262 1846 msgid "Import Views" 1847 msgstr "" 1848 1849 #: includes/class-settings-other.php:285 1850 msgid "View license details and other status information." 1851 msgstr "" 1852 1853 #: includes/class-settings-other.php:325 1854 msgid "Active" 1855 msgstr "" 1856 1857 #: includes/class-settings-other.php:327 1858 msgid "Not Detected" 1859 msgstr "" 1860 1861 #: includes/class-settings-other.php:370 1862 msgid "unknown" 1863 msgstr "" 1864 1865 #: includes/class-settings-other.php:384 1866 msgid "Plugin Version" 1867 msgstr "" 1868 1869 #: includes/class-settings-other.php:392 1870 msgid "Database Tables" 1871 msgstr "" 1872 1873 #: includes/class-settings-other.php:473 1874 msgid "" 1875 "Import view counts when migrating from custom meta key or other analytics " 1876 "plugins." 1877 msgstr "" 1878 1879 #: includes/class-settings-other.php:482 1880 msgid "" 1881 "Choose what happens to stored view data on uninstall, and manage other " 1882 "removal-related tools." 1883 msgstr "" 1884 1885 #: includes/class-settings-reports.php:57 1886 msgid "Display Reports and Export Views to CSV/XML" 1887 msgstr "" 1888 1889 #: includes/class-settings-reports.php:58 1890 msgid "View detailed stats about the popularity of your content." 1891 msgstr "" 1892 1893 #: includes/class-settings-reports.php:59 1894 msgid "Generate views reports in any date range you need." 1895 msgstr "" 1896 1897 #: includes/class-settings-reports.php:60 1898 msgid "Export, download and share your website views data." 1899 msgstr "" 1900 1901 #: includes/class-settings-reports.php:61 includes/class-settings.php:192 1902 msgid "Upgrade to Pro" 1903 msgstr "" 1904 1905 #: includes/class-settings.php:193 1906 msgid "Starting from $29 per year" 1907 msgstr "" 1908 1909 #: includes/class-settings.php:193 1910 msgid "14-day money back guarantee." 1911 msgstr "" 1912 1913 #: includes/class-settings.php:210 1914 msgid "Reliable view counting" 1915 msgstr "" 1916 1917 #: includes/class-settings.php:212 1918 msgid "Accurate counts with caching enabled" 1919 msgstr "" 1920 1921 #: includes/class-settings.php:213 1922 msgid "Better performance under high traffic" 1923 msgstr "" 1924 1925 #: includes/class-settings.php:214 1926 msgid "Protection against fake and repeated views" 1927 msgstr "" 1928 1929 #: includes/class-settings.php:216 1930 msgid "" 1931 "Upgrade to Pro to make your view counts reliable on real-world, cached " 1932 "WordPress sites." 1933 msgstr "" 1934 1935 #: includes/class-settings.php:219 1936 msgid "Accurate & meaningful view display" 1937 msgstr "" 1938 1939 #: includes/class-settings.php:221 1940 msgid "Choose which time period is displayed" 1941 msgstr "" 1942 1943 #: includes/class-settings.php:222 1944 msgid "Always show up-to-date view counts" 1945 msgstr "" 1946 1947 #: includes/class-settings.php:223 1948 msgid "Control where the counter appears" 1949 msgstr "" 1950 1951 #: includes/class-settings.php:225 1952 msgid "" 1953 "Upgrade to Pro to control what view data visitors actually see - not just " 1954 "total counts." 1955 msgstr "" 1956 1957 #: includes/class-settings.php:228 1958 msgid "Advanced view reports" 1959 msgstr "" 1960 1961 #: includes/class-settings.php:230 1962 msgid "" 1963 "Upgrade to Pro to access detailed reports and visual insights for your " 1964 "content." 1965 msgstr "" 1966 1967 #: includes/class-settings.php:233 1968 msgid "Use view counts where they actually matter" 1969 msgstr "" 1970 1971 #: includes/class-settings.php:235 1972 msgid "Display and sort content by popularity" 1973 msgstr "" 1974 1975 #: includes/class-settings.php:236 1976 msgid "Works with the tools you already use" 1977 msgstr "" 1978 1979 #: includes/class-settings.php:237 1980 msgid "No custom queries or advanced setup" 1981 msgstr "" 1982 1983 #: includes/class-settings.php:239 1984 msgid "" 1985 "Upgrade to Pro to use view data across layouts and blocks - not just store " 1986 "it." 1987 msgstr "" 1988 1989 #: includes/class-settings.php:242 1990 msgid "Deeper email summaries" 1991 msgstr "" 1992 1993 #: includes/class-settings.php:244 1994 msgid "Spot content gaining or losing momentum" 1995 msgstr "" 1996 1997 #: includes/class-settings.php:245 1998 msgid "Include author and source summaries" 1999 msgstr "" 2000 2001 #: includes/class-settings.php:246 2002 msgid "Send daily or monthly summaries" 2003 msgstr "" 2004 2005 #: includes/class-settings.php:247 2006 msgid "Add CC/BCC recipients for your team" 2007 msgstr "" 2008 2009 #: includes/class-settings.php:249 2010 msgid "" 2011 "Go beyond a weekly top-content list. Pro adds richer summaries with trends, " 2012 "authors, sources, and flexible delivery options." 2013 msgstr "" 2014 2015 #: includes/class-settings.php:252 2016 msgid "Migrate your view data safely" 2017 msgstr "" 2018 2019 #: includes/class-settings.php:254 2020 msgid "Import view data from other WordPress plugins" 2021 msgstr "" 2022 2023 #: includes/class-settings.php:255 2024 msgid "Choose how existing data is handled" 2025 msgstr "" 2026 2027 #: includes/class-settings.php:256 2028 msgid "Support for posts and other content types" 2029 msgstr "" 2030 2031 #: includes/class-settings.php:258 2032 msgid "" 2033 "Upgrade to Pro to migrate historical view data without losing control over " 2034 "existing counts." 2035 msgstr "" 2036 2037 #: includes/class-settings.php:638 includes/class-settings.php:691 2038 #: includes/class-settings.php:692 2039 msgid "Counting" 2040 msgstr "" 2041 2042 #: includes/class-settings.php:643 includes/class-settings.php:701 2043 #: includes/class-settings.php:702 2044 msgid "Display" 2045 msgstr "" 2046 2047 #: includes/class-settings.php:648 includes/class-settings.php:711 2048 #: includes/class-settings.php:712 includes/class-settings.php:754 2049 msgid "Reports" 2050 msgstr "" 2051 2052 #: includes/class-settings.php:658 includes/class-settings.php:731 2053 #: includes/class-settings.php:732 2054 msgid "Emails" 2055 msgstr "" 2056 2057 #: includes/class-settings.php:663 includes/class-settings.php:741 2058 #: includes/class-settings.php:742 2059 msgid "Other" 2060 msgstr "" 2061 2062 #: includes/class-settings.php:942 2063 msgid "All existing data deleted successfully." 2064 msgstr "" 2065 2066 #: includes/class-settings.php:944 2067 msgid "Error occurred. All existing data were not deleted." 2068 msgstr "" 2069 2070 #: includes/class-settings.php:1088 2071 msgid "NEW!" 2072 msgstr "" 2073 2074 #: includes/class-toolbar.php:132 2075 #, php-format 2076 msgid "%s post view" 2077 msgstr "" 2078 2079 #. translators: 1: month and year, 2: total number of post views 2080 #: includes/class-toolbar.php:140 2081 #, php-format 2082 msgid "Post views chart for %1$s, %2$s total" 2083 msgstr "" 2084 2085 #: includes/class-traffic-signals.php:95 2086 msgid "Traffic Signals" 2087 msgstr "" 2088 2089 #: includes/class-traffic-signals.php:133 2090 msgid "No unusual activity detected." 2091 msgstr "" 2092 2093 #: includes/class-traffic-signals.php:139 2094 msgid "" 2095 "Unusual traffic pattern detected. More insights available in Post Views " 2096 "Counter Pro." 2097 msgstr "" 2098 2099 #: includes/class-update.php:212 2100 msgid "" 2101 "<strong>Post Views Counter</strong> - this version requires a database " 2102 "update. Make sure to back up your database first." 2103 msgstr "" 2104 2105 #: includes/class-update.php:213 2106 msgid "Run the Update" 2107 msgstr "" 2108 2109 #: includes/class-update.php:307 2110 msgid "Thank you! Datebase was successfully updated." 2111 msgstr "" 2112 2113 #: includes/class-widgets.php:55 includes/class-widgets.php:63 2114 msgid "Most Viewed Posts" 2115 msgstr "" 2116 2117 #: includes/class-widgets.php:57 2118 msgid "Displays a list of the most viewed posts" 2119 msgstr "" 2120 2121 #: includes/class-widgets.php:74 2122 msgid "No most viewed posts found" 2123 msgstr "" 2124 2125 #: includes/class-widgets.php:220 2126 msgid "Display post views?" 2127 msgstr "" 2128 2129 #: includes/class-widgets.php:222 2130 msgid "Display post excerpt?" 2131 msgstr "" 2132 2133 #: includes/class-widgets.php:224 2134 msgid "Display post author?" 2135 msgstr "" 2136 2137 #: includes/class-widgets.php:226 2138 msgid "Display post thumbnail?" 2139 msgstr "" 2140 2141 #: post-views-counter.php:772 2142 #, php-format 2143 msgid "" 2144 "Hey, you've been using <strong>Post Views Counter</strong> for more than %s." 2145 msgstr "" 2146 2147 #: post-views-counter.php:772 2148 msgid "" 2149 "Could you please do me a BIG favor and give it a 5-star rating on WordPress " 2150 "to help us spread the word and boost our motivation." 2151 msgstr "" 2152 2153 #: post-views-counter.php:772 2593 #: blocks/pro-placeholder/term-views/block.json 2594 msgctxt "block title" 2595 msgid "Term Views" 2596 msgstr "" 2597 2598 #: blocks/pro-placeholder/term-views/block.json 2599 msgctxt "block description" 2600 msgid "Display views for a given term. Requires Post Views Counter Pro." 2601 msgstr "" 2602 2603 #: blocks/pro-placeholder/term-views/block.json 2604 msgctxt "block keyword" 2605 msgid "term" 2606 msgstr "" 2607 2608 #: blocks/pro-placeholder/user-views/block.json 2609 msgctxt "block title" 2610 msgid "Author Views" 2611 msgstr "" 2612 2613 #: blocks/pro-placeholder/user-views/block.json 2614 msgctxt "block description" 2615 msgid "Display views for a given author. Requires Post Views Counter Pro." 2616 msgstr "" 2617 2618 #: blocks/pro-placeholder/user-views/block.json 2619 msgctxt "block keyword" 2620 msgid "profile" 2621 msgstr "" 2622 2623 #: post-views-counter.php:796 2624 #, php-format 2625 msgid "Hey, you've been using <strong>Post Views Counter</strong> for more than %s." 2626 msgstr "" 2627 2628 #: post-views-counter.php:796 2629 msgid "Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation." 2630 msgstr "" 2631 2632 #: post-views-counter.php:796 2154 2633 msgid "Your help is much appreciated. Thank you very much" 2155 2634 msgstr "" 2156 2635 2157 #: post-views-counter.php:7 722636 #: post-views-counter.php:796 2158 2637 msgid "founder of" 2159 2638 msgstr "" 2160 2639 2161 #: post-views-counter.php:7 722640 #: post-views-counter.php:796 2162 2641 msgid "Ok, you deserve it" 2163 2642 msgstr "" 2164 2643 2165 #: post-views-counter.php:7 722644 #: post-views-counter.php:796 2166 2645 msgid "Nope, maybe later" 2167 2646 msgstr "" 2168 2647 2169 #: post-views-counter.php:7 722648 #: post-views-counter.php:796 2170 2649 msgid "I already did" 2171 2650 msgstr "" 2172 2651 2173 #: post-views-counter.php:1155 2652 #: post-views-counter.php:990 2653 msgid "Post Views Counter could not safely recover data from a previous destructive deactivation. Retry activation after checking the database." 2654 msgstr "" 2655 2656 #: post-views-counter.php:1327 2174 2657 msgid "Are you sure you want to reset these settings to defaults?" 2175 2658 msgstr "" 2176 2659 2177 #: post-views-counter.php:1 1562660 #: post-views-counter.php:1328 2178 2661 msgid "Are you sure you want to delete all existing data?" 2179 2662 msgstr "" 2180 2663 2181 #: post-views-counter.php:1 1572664 #: post-views-counter.php:1329 2182 2665 msgid "Are you sure you want to import views now?" 2183 2666 msgstr "" 2184 2667 2185 #: post-views-counter.php:1 1592668 #: post-views-counter.php:1331 2186 2669 msgid "The test email request did not return a valid response." 2187 2670 msgstr "" 2188 2671 2189 #: post-views-counter.php:1 1602672 #: post-views-counter.php:1332 2190 2673 msgid "The test email request could not be completed. Please try again." 2191 2674 msgstr "" -
post-views-counter/tags/1.8.0/post-views-counter.php
r3647380 r3734102 2 2 /* 3 3 Plugin Name: Post Views Counter 4 Description: Post Views Counter allows you to collect and display how many times a post, page, or other content has been viewed in a simple, fast and reliable way.5 Version: 1. 7.154 Description: Count and display post views, track site-wide visits, and see what content works – inside WordPress. Fast, easy to use and privacy-first. 5 Version: 1.8.0 6 6 Author: dFactory 7 7 Author URI: https://dfactory.co/ … … 11 11 Text Domain: post-views-counter 12 12 Domain Path: /languages 13 Requires at least: 6.4 14 Requires PHP: 7.4 13 15 14 16 Post Views Counter … … 31 33 * 32 34 * @class Post_Views_Counter 33 * @version 1. 7.1535 * @version 1.8.0 34 36 */ 35 37 final class Post_Views_Counter { … … 78 80 ], 79 81 'display' => [ 80 'label' => 'Post Views:', 82 'label' => 'Views:', 83 'frontend_counter_metrics' => 'views', 84 'frontend_template' => '%%icon%% Views: %%views%%', 81 85 'display_period' => 'total', 82 86 'taxonomies' => false, … … 144 148 'schedule_version' => 1 145 149 ], 146 'version' => '1. 7.15'150 'version' => '1.8.0' 147 151 ]; 148 152 149 153 // instances 154 public $columns; 150 155 public $counter; 151 156 public $crawler; … … 158 163 public $settings_api; 159 164 public $import; 165 public $visits; 160 166 161 167 /** … … 184 190 // short init? 185 191 if ( defined( 'SHORTINIT' ) && SHORTINIT ) { 192 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-visits-query.php' ); 193 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-visits.php' ); 186 194 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-counter.php' ); 187 195 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-crawler-detect.php' ); 188 196 include_once( POST_VIEWS_COUNTER_PATH . 'includes/functions.php' ); 189 197 198 self::$instance->visits = new Post_Views_Counter_Visits(); 190 199 self::$instance->counter = new Post_Views_Counter_Counter(); 191 200 self::$instance->crawler = new Post_Views_Counter_Crawler_Detect(); … … 211 220 // initialize other classes 212 221 self::$instance->functions = new Post_Views_Counter_Functions(); 222 self::$instance->visits = new Post_Views_Counter_Visits(); 213 223 214 224 new Post_Views_Counter_Update(); … … 224 234 self::$instance->counter = new Post_Views_Counter_Counter(); 225 235 226 new Post_Views_Counter_Columns();236 self::$instance->columns = new Post_Views_Counter_Columns(); 227 237 new Post_Views_Counter_Columns_Modal(); 228 238 new Post_Views_Counter_Traffic_Signals(); … … 262 272 */ 263 273 private function includes() { 274 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-visits-query.php' ); 264 275 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-functions.php' ); 276 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-visits.php' ); 265 277 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-update.php' ); 266 278 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-settings-api.php' ); … … 290 302 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-frontend.php' ); 291 303 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-dashboard.php' ); 304 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-dashboard-comparison.php' ); 292 305 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-widgets.php' ); 306 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-entrances-eligibility.php' ); 293 307 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-traffic-signals.php' ); 294 308 include_once( POST_VIEWS_COUNTER_PATH . 'includes/class-integration-gutenberg.php' ); … … 939 953 */ 940 954 public function activation( $network ) { 955 $activation_failed = false; 956 941 957 // network activation? 942 958 if ( is_multisite() && $network ) { 943 959 global $wpdb; 944 960 961 if ( $this->visits instanceof Post_Views_Counter_Visits ) 962 $this->visits->reset_network_schema_migration(); 963 945 964 // get all available sites 946 965 $blogs_ids = $wpdb->get_col( 'SELECT blog_id FROM ' . $wpdb->blogs ); … … 950 969 switch_to_blog( (int) $blog_id ); 951 970 952 // run current site activation process 953 $this->activate_site(); 954 955 restore_current_blog(); 956 } 971 try { 972 // Keep network activation on its existing work profile. The bounded 973 // network cursor adds and verifies Visits after activation returns. 974 $activation_failed = ! $this->activate_site_internal( false, true ); 975 } finally { 976 restore_current_blog(); 977 } 978 979 if ( $activation_failed ) 980 break; 981 } 982 983 if ( $this->visits instanceof Post_Views_Counter_Visits ) 984 $this->visits->schedule_schema_sweep(); 985 957 986 } else 958 $this->activate_site(); 987 $activation_failed = ! $this->activate_site_internal( true, true ); 988 989 if ( $activation_failed ) 990 wp_die( esc_html__( 'Post Views Counter could not safely recover data from a previous destructive deactivation. Retry activation after checking the database.', 'post-views-counter' ) ); 959 991 } 960 992 … … 968 1000 */ 969 1001 public function activate_site() { 1002 $this->activate_site_internal( true, false ); 1003 } 1004 1005 /** 1006 * Activate one site with internal migration control. 1007 * 1008 * @global object $wpdb 1009 * @global string $charset_collate 1010 * 1011 * @param bool $migrate_visits Whether to add and verify the Visits schema now. 1012 * @param bool $explicit Whether explicit activation may clear a tombstone. 1013 * @return bool 1014 */ 1015 private function activate_site_internal( $migrate_visits, $explicit = false ) { 970 1016 global $wpdb, $charset_collate; 971 972 // required for dbdelta 973 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); 974 975 // create post views table 976 dbDelta( ' 1017 $activation_state = $this->visits instanceof Post_Views_Counter_Visits ? $this->visits->prepare_site_activation( $explicit ) : 'normal'; 1018 1019 if ( $activation_state === false ) 1020 return false; 1021 1022 try { 1023 if ( $activation_state === 'tombstone' ) { 1024 $table = $wpdb->prefix . 'post_views'; 1025 $wpdb->last_error = ''; 1026 $dropped = $wpdb->query( 'DROP TABLE IF EXISTS ' . $table ); 1027 $remaining = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ); 1028 1029 if ( $dropped === false || $wpdb->last_error !== '' || $remaining !== null ) 1030 return false; 1031 } 1032 1033 // required for dbdelta 1034 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); 1035 1036 // create post views table 1037 dbDelta( ' 977 1038 CREATE TABLE IF NOT EXISTS ' . $wpdb->prefix . 'post_views ( 978 1039 `id` bigint unsigned NOT NULL, … … 980 1041 `period` varchar(8) NOT NULL, 981 1042 `count` bigint unsigned NOT NULL, 1043 ' . ( $migrate_visits ? '`visits` bigint unsigned NOT NULL DEFAULT 0,' : '' ) . ' 982 1044 PRIMARY KEY (type, period, id), 983 1045 UNIQUE INDEX id_type_period_count (id, type, period, count) USING BTREE, 984 1046 INDEX type_period_count (type, period, count) USING BTREE 985 1047 ) ' . $charset_collate . ';' 986 ); 987 988 // add default options 989 add_option( 'post_views_counter_settings_general', $this->defaults['general'], null, false ); 990 add_option( 'post_views_counter_settings_display', $this->defaults['display'], null, false ); 991 add_option( 'post_views_counter_settings_other', $this->defaults['other'], null, false ); 992 add_option( 'post_views_counter_settings_emails', $this->get_default_emails_settings(), null, false ); 993 add_option( 'post_views_counter_version', $this->defaults['version'], null, false ); 994 995 if ( $this->emails_scheduler instanceof Post_Views_Counter_Emails_Scheduler ) 996 $this->emails_scheduler->maybe_schedule( get_option( 'post_views_counter_settings_emails', $this->get_default_emails_settings() ) ); 1048 ); 1049 1050 if ( $activation_state === 'tombstone' ) { 1051 $wpdb->last_error = ''; 1052 $row_count = $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'post_views' ); 1053 1054 if ( $wpdb->last_error !== '' || (int) $row_count !== 0 || ! $this->visits->complete_site_activation() ) 1055 return false; 1056 } 1057 1058 // Verify the additive Visits schema for single-site activation and 1059 // newly initialized sites. Network activation defers this work. 1060 $visits_ready = ! $migrate_visits || ( $this->visits instanceof Post_Views_Counter_Visits && $this->visits->migrate_schema( true ) ); 1061 1062 // add default options 1063 add_option( 'post_views_counter_settings_general', $this->defaults['general'], null, false ); 1064 add_option( 'post_views_counter_settings_display', $this->defaults['display'], null, false ); 1065 add_option( 'post_views_counter_settings_other', $this->defaults['other'], null, false ); 1066 add_option( 'post_views_counter_settings_emails', $this->get_default_emails_settings(), null, false ); 1067 add_option( 'post_views_counter_version', $this->defaults['version'], null, false ); 1068 1069 if ( $migrate_visits && $visits_ready && $this->visits instanceof Post_Views_Counter_Visits ) 1070 $this->visits->refresh_availability( true ); 1071 1072 if ( $this->emails_scheduler instanceof Post_Views_Counter_Emails_Scheduler ) 1073 $this->emails_scheduler->maybe_schedule( get_option( 'post_views_counter_settings_emails', $this->get_default_emails_settings() ) ); 1074 1075 if ( $this->visits instanceof Post_Views_Counter_Visits ) 1076 $this->visits->schedule_schema_sweep(); 1077 1078 return $visits_ready; 1079 } finally { 1080 if ( $this->visits instanceof Post_Views_Counter_Visits ) 1081 $this->visits->finish_site_activation(); 1082 } 997 1083 } 998 1084 … … 1025 1111 if ( is_multisite() && $network ) { 1026 1112 global $wpdb; 1113 $blocked_deactivation = false; 1027 1114 1028 1115 // get all available sites … … 1030 1117 1031 1118 foreach ( $blogs_ids as $blog_id ) { 1032 // change to another site 1033 switch_to_blog( (int) $blog_id ); 1034 1035 // run current site deactivation process 1036 $this->deactivate_site( true ); 1037 1038 restore_current_blog(); 1039 } 1119 $switched = (int) get_current_blog_id() !== (int) $blog_id; 1120 1121 // Avoid an unnecessary callback-capable switch for the origin site. 1122 if ( $switched ) 1123 switch_to_blog( (int) $blog_id ); 1124 1125 try { 1126 // run current site deactivation process 1127 $deactivation = $this->deactivate_site_internal( true ); 1128 $blocked_deactivation = in_array( $deactivation, [ 'measurement_fence_unlock_failed', 'schema_lease_retry_blocked' ], true ); 1129 } finally { 1130 // A failed UNLOCK TABLES leaves this connection restricted to the 1131 // current site's locked tables. restore_current_blog() can dispatch 1132 // callbacks, so preserve the switched context for request recovery. 1133 if ( ! $blocked_deactivation && $switched ) 1134 restore_current_blog(); 1135 } 1136 1137 if ( $blocked_deactivation ) 1138 break; 1139 } 1140 1141 if ( ! $blocked_deactivation && $this->visits instanceof Post_Views_Counter_Visits ) 1142 $this->visits->delete_network_state(); 1040 1143 } else 1041 1144 $this->deactivate_site(); … … 1052 1155 */ 1053 1156 public function deactivate_site( $multi = false ) { 1054 if ( $this->emails_scheduler instanceof Post_Views_Counter_Emails_Scheduler ) 1055 $this->emails_scheduler->clear(); 1056 else 1057 wp_clear_scheduled_hook( 'pvc_weekly_content_summary_send' ); 1058 1157 $this->deactivate_site_internal( $multi ); 1158 } 1159 1160 /** 1161 * Deactivate one site and return an internal failed-unlock signal only to 1162 * the network coordinator. The public deactivate_site() API stays void. 1163 * 1164 * @param bool $multi 1165 * @return bool|string 1166 */ 1167 private function deactivate_site_internal( $multi = false ) { 1059 1168 if ( $multi === true ) { 1060 1169 $options = get_option( 'post_views_counter_settings_other', [] ); … … 1063 1172 $check = $this->options['other']['deactivation_delete']; 1064 1173 1174 if ( $check && $this->visits instanceof Post_Views_Counter_Visits ) { 1175 $deletion = $this->visits->delete_site_state(); 1176 1177 if ( $deletion === 'measurement_fence_unlock_failed' ) { 1178 // Deactivation is a one-shot lifecycle event. The failed unlock keeps 1179 // Core's FIFO, tombstone, and schema lease as durable retry obligations; 1180 // do not move the derived boundary, clear schedules, or publish any acknowledgement. 1181 error_log( 'Post Views Counter: destructive deactivation stopped because its protected table fence could not be released; retry deactivation after recovery.' ); 1182 return 'measurement_fence_unlock_failed'; 1183 } 1184 1185 if ( $deletion === 'schema_lease_retry_blocked' ) { 1186 // A fresh retry cannot safely continue while the failed request's 1187 // durable schema lease remains unexpired. Keep all lifecycle cleanup 1188 // and acknowledgement work for the later takeover-capable retry. 1189 error_log( 'Post Views Counter: destructive deactivation remains blocked by its retained schema lease; retry after lease expiry or takeover.' ); 1190 return 'schema_lease_retry_blocked'; 1191 } 1192 1193 if ( ! $deletion ) { 1194 $check = false; 1195 error_log( 'Post Views Counter: destructive deactivation was skipped because Visit cache state could not be retired safely.' ); 1196 } 1197 } 1198 1199 if ( $check ) { 1200 global $wpdb; 1201 $table = $wpdb->prefix . 'post_views'; 1202 $wpdb->last_error = ''; 1203 $dropped = $wpdb->query( 'DROP TABLE IF EXISTS ' . $table ); 1204 $remaining = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ); 1205 1206 if ( $dropped === false || $wpdb->last_error !== '' || $remaining !== null ) { 1207 $check = false; 1208 error_log( 'Post Views Counter: destructive deactivation table cleanup failed; the queue-generation tombstone was retained.' ); 1209 } 1210 1211 if ( $this->visits instanceof Post_Views_Counter_Visits ) 1212 $this->visits->finish_site_state_deletion(); 1213 } 1214 1215 if ( ! $check && $this->visits instanceof Post_Views_Counter_Visits ) 1216 $this->visits->suspend_live_visit_writes( 'core_deactivated' ); 1217 1218 if ( $this->emails_scheduler instanceof Post_Views_Counter_Emails_Scheduler ) 1219 $this->emails_scheduler->clear(); 1220 else 1221 wp_clear_scheduled_hook( 'pvc_weekly_content_summary_send' ); 1222 1065 1223 // delete options if needed 1066 1224 if ( $check ) { 1067 // Give a compatible Proclient one non-blocking opportunity to1225 // Give a compatible extension client one non-blocking opportunity to 1068 1226 // release the remote license before Free removes shared settings. 1069 1227 if ( function_exists( 'Post_Views_Counter_Pro' ) ) { … … 1085 1243 delete_transient( 'post_views_counter_ip_cache' ); 1086 1244 1087 global $wpdb;1088 1089 // delete table from database1090 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'post_views' );1091 1245 } 1092 1246 … … 1094 1248 wp_clear_scheduled_hook( 'pvc_reset_counts' ); 1095 1249 1250 if ( $this->visits instanceof Post_Views_Counter_Visits ) 1251 $this->visits->clear_schema_sweep(); 1252 1096 1253 remove_action( 'pvc_reset_counts', [ $this->cron, 'reset_counts' ] ); 1254 1255 return true; 1097 1256 } 1098 1257 … … 1109 1268 switch_to_blog( $site->blog_id ); 1110 1269 1111 // run current site activation process 1112 $this->activate_site(); 1113 1114 restore_current_blog(); 1270 try { 1271 // run current site activation process 1272 if ( ! $this->activate_site_internal( true, false ) ) 1273 error_log( 'Post Views Counter: new-site initialization remained fail-closed.' ); 1274 } finally { 1275 restore_current_blog(); 1276 } 1115 1277 } 1116 1278 } … … 1213 1375 1214 1376 // prepare script data 1377 // Bulk Edit counter writes happen server-side on the native 1378 // bulk_edit_posts completion hook. No shipped script calls the 1379 // retained save_bulk_post_views compatibility endpoint, so its 1380 // nonce is no longer printed. 1215 1381 $script_data = [ 1216 'nonce' => wp_create_nonce( 'pvc_save_bulk_post_views' ),1217 1382 'wpVersion59' => version_compare( $wp_version, '5.9', '>=' ) 1218 1383 ]; -
post-views-counter/tags/1.8.0/readme.txt
r3647380 r3734102 2 2 Contributors: dfactory 3 3 Tags: counter, postviews, statistics, analytics, pageviews 4 Requires at least: 6. 3.05 Requires PHP: 7. 04 Requires at least: 6.4 5 Requires PHP: 7.4 6 6 Tested up to: 7.1 7 Stable tag: 1. 7.157 Stable tag: 1.8.0 8 8 License: MIT 9 9 License URI: http://opensource.org/licenses/MIT 10 10 11 Post Views Counter allows you to collect and display how many times a post, page, or other content has been viewed in a simple, fast and reliable way.11 Count and display post views, track site-wide visits, and see what content works – inside WordPress. Fast, easy to use and privacy-first. 12 12 13 13 == Description == 14 14 15 Post Views Counter allows you to collect and display how many times a post, page, or other content has been viewed in a simple, fast and reliable way. 16 17 [Post Views Counter](https://postviewscounter.com/) gives you clear, accurate post view stats — right inside WordPress. No external tools. No bloat. Just the numbers you need to see what’s working. 15 [Post Views Counter](https://postviewscounter.com/) counts how many times your posts, pages and other content are viewed, shows those counts on your site, and helps you see which content works – right inside WordPress. No external tools. No bloat. Just the numbers you need to see what’s working. 16 17 It counts two things: 18 19 - **Views** – Counted views of your selected posts, pages and other content, according to your counting settings. Views can be displayed on your site and used to sort content. 20 - **Visits** – A Visit starts with a browser’s first counted view and covers subsequent counted content views within the fixed Count Interval. Visits are shown as site-wide totals beside Views, not per post. 18 21 19 22 = Key Benefits = … … 21 24 Clarity, speed, and control: 22 25 23 - **Clear, Focused Metrics** — You get a clear picture of how your posts are performing. 24 - **Made for WordPress** — Runs entirely in your site. No GA, no third-party pipes; accurate counts in your Dashboard. 25 - **Privacy-first** — Data lives on your server, with controls that respect visitors’ rights and privacy regulations. 26 - **Works at scale** — Minimal overhead, no external scripts, Multisite-ready. 27 - **Display anywhere** — Automatically show counts, or place them exactly where you want via blocks or shortcode. 26 - **Clear, Focused Metrics** – Views for every post and Visits for the whole site give you a clear picture of how your content is performing. 27 - **Made for WordPress** – Runs entirely in your site. No GA, no third-party pipes; accurate counts in your Dashboard and post lists. 28 - **Your counting rules** – Choose which content to count, exclude selected visitors, and set the interval for repeat counts. 29 - **Privacy-first** – Views and Visits are stored as aggregate totals on your server. Browser storage helps prevent repeat counting within your Count Interval. Pro offers cookieless browser storage; its optional Strict Counts feature also caches IP-derived data to limit repeat counts. 30 - **Works at scale** – Minimal overhead, no external scripts, Multisite-ready. 31 - **Display anywhere** – Automatically show counts, or place them exactly where you want via blocks, shortcode or PHP. 28 32 29 33 = Features = … … 32 36 33 37 - Count & display views for **any post type** you select. 38 - Count **Visits** and see them beside Views in the dashboard chart. 34 39 - Three counting modes: **PHP, JavaScript, REST API** 35 - Dashboard post views **stats widget** 36 - Sortable Post Views **admin column** 40 - **Post Views dashboard widget**: a chart of Views, Visits or both, with a Views comparison for the selected month. A month in progress is compared with the same days of the previous month. 41 - **Top Posts dashboard widget**, month by month. 42 - Sortable Post Views **admin column**, with a Views chart for each post. 43 - **Traffic Signals** admin column that flags unusual traffic changes compared with the same days of the previous month. 44 - **Weekly email summary** of how your content performed. 37 45 - Exclude bots, logged-in users, specific roles, or IPs 38 46 - Manually adjust a post’s views when needed. 39 47 - Query and **order content by views** (developer-friendly) 40 48 - Custom REST API endpoints 41 - Option to set count interval49 - **Count Interval** to set the fixed window for repeat counts from the same browser. 42 50 - One-click data import from **WP-PostViews**, **Statify** and **Page Views Count** 43 - Post views **display position**, automatic or manual via shortcode 44 - **Multisite** compatibile 51 - Show the counter automatically, or place it with the **Post Views block**, shortcode or PHP function. 52 - **Most Viewed Posts** block and widget. 53 - **Multisite** compatible 45 54 - **WPML/Polylang** compatible; translation-ready (.pot) 46 55 … … 49 58 More capability without extra complexity: 50 59 51 - **Fast AJAX counting** for more accurate data. 52 - **Caching optimization** that guarantees performance even under heavy traffic. 53 - **Reports**: Views by Date, Post, Author to spot winners, trends, and top contributors. 60 - **Fast AJAX counting** that keeps counting light on busy sites. 61 - **Caching compatibility** and dynamic loading to count through cached pages and refresh displayed counts when a compatible counting mode is selected. 62 - **Reports**: Views by Date, Post and Author to spot winners, trends and top contributors, plus **Visits in aggregate date reports**. 63 - **Visit trends and Views per visit** in dashboard insights and email summaries. 64 - **Performance Insights** that explain how a post’s Views changed, in the admin column, Traffic Signals and email summaries. 65 - **Daily, weekly and monthly email summaries** with insights. 66 - **Traffic sources**: aggregate stats on referrers, devices, browsers, operating systems and languages. 67 - Views for **taxonomy terms, authors** and other archives. 54 68 - Customizable **Views Period** (e.g., last 7/30 days) to control the views count timeframe. 55 69 - **Export to CSV/XML** to download and share data. … … 70 84 = Why use Post Views Counter vs Google Analytics? = 71 85 72 Post Views Counter gives you clean, per-post view counts inside WordPress — fast, cache-friendly, and privacy-first, with data that stays on your server. Google Analytics might be an overkill when you just need accurate post/page views for editorial decisions.86 Post Views Counter gives you per-post Views and site-wide Visits inside WordPress. It is fast, easy to use and privacy-first, with counting data stored on your server and control over what, who and when you count. Google Analytics may be more than you need when you want content view statistics for editorial decisions. 73 87 74 88 = Can I use Post Views Counter alongside Google Analytics? = 75 89 76 Of course — many sites use both. Post Views Counter handles on-site, per-post view counts inside WordPress (no third-party scripts), while Google Analytics covers marketing funnels and acquisition. 90 Of course – many sites use both. Post Views Counter handles on-site, per-post view counts inside WordPress (no third-party scripts), while Google Analytics covers marketing funnels and acquisition. 91 92 = What is the difference between Views and Visits? = 93 94 A View belongs to the content being viewed and is counted according to your counting settings. A Visit starts with a browser’s first counted view and covers subsequent counted content views within the fixed Count Interval. Viewing another eligible post within that window adds a View without starting another Visit. Later views do not extend the window. 95 96 = Why do Visits differ from sessions in Google Analytics? = 97 98 Post Views Counter follows the counting rules you choose: which content to count, which visitors to include or exclude, and how often to count them again. These rules may differ from your Google Analytics setup, so the totals are not expected to match. 99 100 The time windows also differ. PVC starts a fixed Visit window with the first counted view, using your Count Interval – 24 hours by default. Later views do not extend it. Google Analytics 4 uses an inactivity timeout, which defaults to 30 minutes. 101 102 = Why can’t I see Visits for a single post? = 103 104 A Visit belongs to your site, not to a post – one Visit often covers several posts. Post Views Counter shows Views for each post and Visits as site-wide totals. Traffic Signals still notice when the visits that start on a post change unusually. 105 106 = Why does the Visits chart show no data? = 107 108 Visits start accumulating when Visit counting becomes available; earlier Views do not automatically become Visits. Setting Count Interval to 0 stops new Visits but preserves previously counted totals. If browser storage is unavailable, Views can still be counted but Visits are not inferred. Right after an update, the chart can briefly say that Visit data is not available while the database is prepared. 77 109 78 110 = Is Post Views Counter GDPR compliant? = 79 111 80 Post Views Counter runs entirely inside WordPress with no third-party scripts and keeps data on your server — aligning with GDPR-style expectations.112 Post Views Counter counts views and visits inside WordPress without third-party tracking scripts. Views and Visits are stored as aggregate totals on your server. To apply the Count Interval, it uses a first-party cookie in the visitor’s browser. Pro also offers cookieless browser storage; its optional Strict Counts feature caches IP-derived data associated with content and timestamps to limit repeat counts. 81 113 82 114 = How do I get support? = … … 92 124 93 125 == Changelog == 126 127 = 1.8.0 = 128 * New: Site-wide Visits tracking. 129 * New: Views, Visits and combined display modes in the Post Views dashboard chart. 130 * New: Monthly Views comparisons in the Post Views dashboard widget. 131 * New: Custom Format for frontend Views counters in Display settings, shortcodes and PHP functions. 132 * New: Traffic Signals for changes in visits starting on a post. 133 * Fix: Block editor counter editing permissions, duplicate saves and error reporting. 134 * Fix: Counter input validation and Bulk Edit updates for saved posts. 135 * Fix: Access checks for admin column Views charts. 136 * Fix: Exclude non-post counts from post charts and summary emails. 137 * Fix: Traffic Signals and modal periods follow Count Time, including month-end comparisons. 138 * Fix: Preserve daily history when Cleanup Interval is set to 0. 139 * Fix: Prevent false Traffic Signals when daily history is incomplete. 140 * Fix: Keep keyboard focus inside the Views chart modal after navigating between periods. 141 * Fix: Restore the Views counter in the block editor on WordPress 6.4. 142 * Fix: Restore lifetime totals in pvc_get_views() when no period is specified. 143 * Tweak: Limit form-based counter edits to the submitted post; use pvc_update_post_views() for programmatic updates. 144 * Tweak: Use stored totals for manual Views edits, independently of pvc_get_post_views filters. 145 * Tweak: Remove pvcArgsQuickEdit.nonce from post lists; retain the save_bulk_post_views AJAX action for compatibility. 146 * Tweak: Reduce Traffic Signals reads to one database query per posts list page. 147 * Tweak: Use native Views column sorting with a stable tie-break. 148 * Tweak: Unify the frontend counter label to Views. 149 * Tweak: Replace frontend Dashicons with a CSS counter icon. 150 * Tweak: Retire the Icon Class setting; custom icons now require the pvc_counter_icon_class or pvc_counter_icon filter. 94 151 95 152 = 1.7.15 = … … 495 552 == Upgrade Notice == 496 553 497 = 1. 7.15=498 Improves Statify import reliability and WordPress 7.1 editor compatibility.554 = 1.8.0 = 555 Adds site-wide Visits, dashboard comparisons and Custom Format for the Views counter, with counting and editing fixes. If you use Pro, update both plugins and purge full-page caches so dynamic counters use the new markup.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)