In-Person Live Courses with Denis Brown
try { function noopFunc(){};;function noopCallbackFunc(){return noopFunc};;function trueFunc(){return true};;function falseFunc(){return false};;function noopArray(){return []};;function noopObject(){return {}};;function throwFunc(){throw new Error()};;function getRequestData(t){return Object.fromEntries(getRequestProps().map(function(n){var r=t[n];return[n,r]}))};;function forgeResponse(e,t){var s=e.bodyUsed,r=e.headers,u=e.ok,a=e.redirected,d=e.status,o=e.statusText,l=e.type,n=e.url,v=new Response(t,{status:d,statusText:o,headers:r});return Object.defineProperties(v,{url:{value:n},type:{value:l},ok:{value:u},bodyUsed:{value:s},redirected:{value:a}}),v};;function getFetchData(n,a){var e,t,c={},r=n[0];if(r instanceof Request){var f=a.call(r),i=getRequestData(f);e=i.url,t=i}else e=r,t=n[1];return c.url=e,t instanceof Object&&Object.keys(t).forEach(function(n){c[n]=t[n]}),c};;function getXhrData(t,n,r,a,e){return{method:t,url:n,async:r,user:a,password:e}};;function escapeRegExp(e){return e.replace(/[.*+?^${}()|[]\]/g,"\$&")};;function isValidParsedData(e){return Object.values(e).every(function(e){return isValidStrPattern(e)})};;function isValidStrPattern(t){var r,n=escapeRegExp(t);"/"===t[0]&&"/"===t[t.length-1]&&(n=t.slice(1,-1));try{r=RegExp(n),r=!0}catch(a){r=!1}return r};;function getMatchPropsData(t){var a={};return Object.keys(t).forEach(function(n){a[n]=toRegExp(t[n])}),a};;function parseMatchProps(r){var e={};return r.split(" ").forEach(function(r){var i,c=r.indexOf(":"),n=r.slice(0,c);if(i=n,getRequestProps().includes(i)){var s=r.slice(c+1);e[n]=s}else e.url=r}),e};;function matchRequestProps(r,e){if(""===r||"*"===r)return!0;var t,n=parseMatchProps(r);if(isValidParsedData(n)){var a=getMatchPropsData(n);t=Object.keys(a).every(function(r){var t=a[r],n=e[r];return Object.prototype.hasOwnProperty.call(e,r)&&"string"==typeof n&&(null==t?void 0:t.test(n))})}else console.log("Invalid parameter: ".concat(r)),t=!1;return t};;function getRequestProps(){return["url","method","headers","body","credentials","cache","redirect","referrer","referrerPolicy","integrity","keepalive","signal","mode"]};;function objectToString(n){return n&&"object"==typeof n?isEmptyObject(n)?"{}":Object.entries(n).map(function(n){var t=n[0],o=n[1],c=o;return o instanceof Object&&(c="{ ".concat(objectToString(o)," }")),"".concat(t,':"').concat(c,'"')}).join(" "):String(n)};;function noopPromiseResolve(e="{}",t="",u="default"){if("undefined"==typeof Response)return;let n=new Response(e,{status:200,statusText:"OK"});return Object.defineProperties(n,{url:{value:t},type:{value:u}}),Promise.resolve(n)};;function noopPromiseReject(){return Promise.reject()};;function isIframe(){try{return window.self!==window.top}catch(r){return!0}};function isDelayMatched(e,n){return"*"===e||n===getMatchDelay(e)};;function nativeIsNaN(N){let a=Number.isNaN||window.isNaN;return a(N)};;function isEmptyObject(t){return 0===Object.keys(t).length&&!t.prototype};;function isValidCallback(n){return n instanceof Function||"string"==typeof n};;function nativeIsFinite(i){let n=Number.isFinite||window.isFinite;return n(i)};;function getMatchDelay(t){let e=parseInt(t,10),n=nativeIsNaN(e)?1000:e;return n};;function getBoostMultiplier($){let t=parseFloat($),e=nativeIsNaN(t)||!nativeIsFinite(t)?.05:t;return e<.001&&(e=.001),e>50&&(e=50),e};;function safeGetDescriptor(e,r){let t=Object.getOwnPropertyDescriptor(e,r);return t&&t.configurable?t:null};;function createOnErrorHandler(n){let r=window.onerror;return function e(t,...o){return!!("string"==typeof t&&t.includes(n))||r instanceof Function&&r.apply(window,[t,...o])}};;function setPropertyAccess(e,r,t){let n=Object.getOwnPropertyDescriptor(e,r);return(!n||!!n.configurable)&&(Object.defineProperty(e,r,t),!0)};;function getDescriptorAddon(){return{isAbortingSuspended:!1,isolateCallback(t,...e){this.isAbortingSuspended=!0;try{let i=t(...e);return this.isAbortingSuspended=!1,i}catch{let n=randomId();throw this.isAbortingSuspended=!1,ReferenceError(n)}}}};;function getPropertyInChain(e,n){let t=n.indexOf(".");if(-1===t)return{base:e,prop:n};let r=n.slice(0,t);if(null===e)return{base:e,prop:r,chain:n};let i=e[r];return(n=n.slice(t+1),(e instanceof Object||"object"==typeof e)&&isEmptyObject(e)||null===i)?{base:e,prop:r,chain:n}:void 0!==i?getPropertyInChain(i,n):(Object.defineProperty(e,r,{configurable:!0}),{base:e,prop:r,chain:n})};;function randomId(){return Math.random().toString(36).slice(2,9)};;function getNativeRegexpTest(){let t=Object.getOwnPropertyDescriptor(RegExp.prototype,"test"),e=t?.value;if(t&&"function"==typeof t.value)return e;throw Error("RegExp.prototype.test is not a function")};;function shouldAbortInlineOrInjectedScript(t,e){let i="injectedScript",l=t=>t.includes("inlineScript"),r=t=>t.includes(i);if(!(l(t)||r(t)))return!1;let n=window.location.href,s=n.indexOf("#");-1!==s&&(n=n.slice(0,s));let c=e.split("n").slice(2).map(t=>t.trim()),d=c.map(t=>{let e,l=/(.*?@)?(S+)(:d+):d+)?$/.exec(t);if(l){let r=l[2];if(r?.startsWith("(")&&(r=r.slice(1)),r?.startsWith("")){r=i;let n=void 0!==l[1]?l[1].slice(0,-1):t.slice(0,l.index).trim();n?.startsWith("at")&&(n=n.slice(2).trim()),e=`${n} ${r}`.trim()}else e=r}else e=t;return e});if(d){for(let a=0;at.trim()).join("n");return getNativeRegexpTest().call(c,i)};;function getWildcardPropertyInChain(r,e,i=!1,t=[]){let l=e.indexOf(".");if(-1===l){if("*"===e||"[]"===e)for(let n in r)Object.prototype.hasOwnProperty.call(r,n)&&t.push({base:r,prop:n});else t.push({base:r,prop:e});return t}let o=e.slice(0,l),a="[]"===o&&Array.isArray(r)||"*"===o&&r instanceof Object;if(a){let p=e.slice(l+1),c=Object.keys(r);c.forEach(e=>{let l=r[e];getWildcardPropertyInChain(l,p,i,t)})}Array.isArray(r)&&r.forEach(r=>{let l=r;void 0!==l&&getWildcardPropertyInChain(l,e,i,t)});let d=r[o];return e=e.slice(l+1),void 0!==d&&getWildcardPropertyInChain(d,e,i,t),t};;function jsonPruner(t,e,o,r){if(0===e.length&&0===o.length)return console.log(`${window.location.hostname}${JSON.stringify(t,null,2)}Stack trace:${Error().stack}`,!0),t&&"object"==typeof t&&console.log(t,!0,!1),t;try{if(!1===isPruningNeeded(t,e,o,r))return t;e.forEach(e=>{let o=getWildcardPropertyInChain(t,e,!0);o.forEach(t=>{void 0!==t&&t.base&&delete t.base[t.prop]})})}catch(n){console.log(n)}return t};;function isPruningNeeded(t,e,n,l){if(!t)return!1;let i;if(0===e.length&&n.length>0){let r=JSON.stringify(t);if(toRegExp(n.join("")).test(r))return console.log(`${window.location.hostname}${JSON.stringify(t,null,2)}Stack trace:${Error().stack}`,!0),t&&"object"==typeof t&&console.log(t,!0,!1),i=!1}if(l&&!matchStackTrace(l,Error().stack||""))return!1;let o=[".*.","*.",".*",".[].","[].",".[]"];for(let f=0;fs.includes(t)),c=getWildcardPropertyInChain(t,s,a);if(!c.length){i=!1;break}i=!a;for(let u=0;u0&&void 0!==arguments[0]?arguments[0]:"";if(""===t)return RegExp(".?");var r,e,n=t.lastIndexOf("/"),i=t.substring(n+1),s=t.substring(0,n+1),a=(r=s,e=i,r.startsWith("/")&&r.endsWith("/")&&!r.endsWith("\/")&&function t(r){if(!r)return!1;try{return RegExp("",r),!0}catch(e){return!1}}(e)?e:"");return t.startsWith("/")&&t.endsWith("/")||a?RegExp((a?s:t).slice(1,-1),a):RegExp(t.replace(//'/g, "'").replace(/\"/g,'"').replace(/[.*+?^${}()|[]\]/g,"\$&"))};;function parseNodeTextParams(t,s,e=null){let r=!(t.startsWith("/")&&t.endsWith("/")),a=r?t:toRegExp(t),i=s.startsWith("/")?toRegExp(s):s,n;return e&&(n=e.startsWith("/")?toRegExp(e):e),{selector:r?t:"*",nodeNameMatch:a,textContentMatch:i,patternMatch:n}};;function isTargetNode(e,t,n){let{nodeName:s,textContent:o}=e,i=s.toLowerCase();return null!==o&&""!==o&&(t instanceof RegExp?t.test(i):t===i)&&(n instanceof RegExp?n.test(o):o.includes(n))};;function replaceNodeText(e,t,n){let{textContent:o}=e;o&&!e.id&&(e.textContent=o.replace(t,n),console.log("textContent",e))};;function nodeListToArray(t){let e=[];for(let n=0;n{o.disconnect(),e(t,o),o.observe(document.documentElement,n)});o.observe(document.documentElement,n),"number"==typeof t&&setTimeout(()=>o.disconnect(),t)};;function handleMutations(n,t){let a=getAddedNodes(n);t(a)};;function hitFunction(e){if(!0===e.verbose){try{const n=console.log.bind(console),t=console.trace.bind(console);let o=e.ruleText||"";if(e.domainName){const n="#%#//",t="##+js";let c;e.ruleText.includes(n)?c=e.ruleText.indexOf(n):e.ruleText.includes(t)&&(c=e.ruleText.indexOf(t));const i=e.ruleText.slice(c);o=`${e.domainName}${i}`}n(`${o} trace start`),t&&t(),n(`${o} trace end`)}catch(e){}"function"==typeof window.__debug&&window.__debug(e)}};function substringAfter(n,t){if(!n)return n;const r=n.indexOf(t);return r<0?"":n.substring(r+t.length)};function substringBefore(n,r){if(!n||!r)return n;const t=n.indexOf(r);return t<0?n:n.substring(0,t)};function logMessage(o,e,n=!1,s=!0){const{name:c,verbose:t}=o;if(!n&&!t)return;const g=console.log;s?g(`${c}: ${e}`):g(`${c}:`,e)};function noopNull(){return null};function getPreventGetter(e){return(n,t)=>(!t||"closed"!==t)&&("function"==typeof e?noopFunc:t&&n[t])};function createDecoy(e){let t,o;!function(e){e.Object="object",e.Iframe="iframe"}(t||(t={})),function(e){e.Object="data",e.Iframe="src"}(o||(o={}));const{replacement:r,url:n,delay:c}=e;let a;a="obj"===r?t.Object:t.Iframe;const m=document.createElement(a);return m instanceof HTMLObjectElement?m[o.Object]=n:m instanceof HTMLIFrameElement&&(m[o.Iframe]=n),m.style.setProperty("height","1px","important"),m.style.setProperty("position","fixed","important"),m.style.setProperty("top","-1px","important"),m.style.setProperty("width","1px","important"),document.body.appendChild(m),setTimeout((()=>m.remove()),1e3*c),m};function handleOldReplacement(e){let n;if(e){if("trueFunc"===e)n=trueFunc;else if(e.includes("=")){if(e.startsWith("{")&&e.endsWith("}")){const t=e.slice(1,-1),s=substringBefore(t,"=");"noopFunc"===substringAfter(t,"=")&&(n={},n[s]=noopFunc)}}}else n=noopFunc;return n};function parseMatchArg(t){const e=!!t&&t?.startsWith("!"),a=e?t.slice(1):t;return{isInvertedMatch:e,matchRegexp:toRegExp(a),matchValue:a}};function isValidMatchStr(t){let i=t;return t?.startsWith("!")&&(i=t.slice(1)),isValidStrPattern(i)};function parseRawDelay(a){const e=Math.floor(parseInt(a,10));return"number"!=typeof e||nativeIsNaN(e)?a:e};function isValidMatchNumber(t){let i=t;t?.startsWith("!")&&(i=t.slice(1));const a=parseFloat(i);return!nativeIsNaN(a)&&nativeIsFinite(a)};function parseDelayArg(t){const a=t?.startsWith("!"),e=a?t.slice(1):t,n=parseInt(e,10);return{isInvertedDelayMatch:a,delayMatch:nativeIsNaN(n)?null:n}};function isPreventionNeeded({callback:a,delay:e,matchCallback:t,matchDelay:l}){if(!isValidCallback(a))return!1;if(!isValidMatchStr(t)||l&&!isValidMatchNumber(l))return!1;const{isInvertedMatch:r,matchRegexp:c}=parseMatchArg(t),{isInvertedDelayMatch:i,delayMatch:n}=parseDelayArg(l),s=parseRawDelay(e);let d=!1;const h=String(a);return d=null===n?c.test(h)!==r:t?c.test(h)!==r&&s===n!==i:s===n!==i,d};function setConstant(e,t,i="",s=""){if(!e||!matchStackTrace(i,Error().stack))return;let l=noopArray(),n=noopObject(),o;if("undefined"===t)o=void 0;else if("false"===t)o=!1;else if("true"===t)o=!0;else if("null"===t)o=null;else if("emptyArr"===t)o=l;else if("emptyObj"===t)o=n;else if("noopFunc"===t)o=noopFunc;else if("noopCallbackFunc"===t)o=noopCallbackFunc;else if("trueFunc"===t)o=trueFunc;else if("falseFunc"===t)o=falseFunc;else if("throwFunc"===t)o=throwFunc;else if("noopPromiseResolve"===t)o=noopPromiseResolve;else if("noopPromiseReject"===t)o=noopPromiseReject;else if(/^d+$/.test(t)){if(nativeIsNaN(o=parseFloat(t))||Math.abs(o)>32767)return}else if("-1"===t)o=-1;else if(""===t)o="";else if("yes"===t)o="yes";else{if("no"!==t)return;o="no"}["asFunction","asCallback","asResolved","asRejected",].includes(s)&&(o=({asFunction:e=>()=>e,asCallback:e=>()=>()=>e,asResolved:e=>Promise.resolve(e),asRejected:e=>Promise.reject(e)})[s](o));let f=!1,r=e=>f||(f=void 0!==e&&void 0!==o&&typeof e!=typeof o&&null!==e),a=(e,t,i,s)=>{if(!s.init(e[t]))return!1;let l=Object.getOwnPropertyDescriptor(e,t),n;if(l instanceof Object){if(!l.configurable){let f=`Property '${t}' is not configurable`;return console.log(f),!1}e[t]=o,l.set instanceof Function&&(n=l.set)}return Object.defineProperty(e,t,{configurable:i,get:()=>s.get(),set(e){void 0!==n&&n(e),s.set(e)}}),!0},u=(e,t)=>{let i=getPropertyInChain(e,t),{base:s}=i,{prop:l,chain:n}=i,f={factValue:void 0,init(e){return this.factValue=e,!0},get(){return this.factValue},set(e){this.factValue!==e&&(this.factValue=e,e instanceof Object&&u(e,n))}};if(!n){let c=a(s,l,!1,{init:e=>!r(e),get:()=>o,set(e){r(e)&&(o=e)}});c&&console.log(`Property '${l}' is trapped`);return}if(void 0!==s&&null===s[l]){a(s,l,!0,f);return}(s instanceof Object||"object"==typeof s)&&isEmptyObject(s)&&a(s,l,!0,f);let p=e[l];(p instanceof Object||"object"==typeof p&&null!==p)&&u(p,n),a(s,l,!0,f)};u(window,e)};;function trustedReplaceXhrResponse(e="",t="",r=""){if("undefined"==typeof Proxy)return;if(""===e&&""!==t){console.log("Pattern argument should not be empty string.");return}let l=""===e&&""===t,a=window.XMLHttpRequest.prototype.open,p=window.XMLHttpRequest.prototype.send,n,s=(e,t,a)=>{if(n=getXhrData.apply(null,a),l){let p=`xhr( ${objectToString(n)} )`;return console.log(p,!0),Reflect.apply(e,t,a)}if(matchRequestProps(r,n)&&(t.shouldBePrevented=!0),t.shouldBePrevented){t.collectedHeaders=[];let s=(e,t,r)=>(t.collectedHeaders.push(r),Reflect.apply(e,t,r));t.setRequestHeader=new Proxy(t.setRequestHeader,{apply:s})}return Reflect.apply(e,t,a)},o=(r,l,s)=>{if(!l.shouldBePrevented)return Reflect.apply(r,l,s);let o=new XMLHttpRequest;o.addEventListener("readystatechange",()=>{if(4!==o.readyState)return;let{readyState:r,response:a,responseText:p,responseURL:n,responseXML:s,status:d,statusText:u}=o,i=p||a;if("string"!=typeof i)return;let y="*"===e?/(n|.)*/:toRegExp(e),c=i.replace(y,t);Object.defineProperties(l,{readyState:{value:r,writable:!1},responseURL:{value:n,writable:!1},responseXML:{value:s,writable:!1},status:{value:d,writable:!1},statusText:{value:u,writable:!1},response:{value:c,writable:!1},responseText:{value:c,writable:!1}}),setTimeout(()=>{let e=new Event("readystatechange");l.dispatchEvent(e);let t=new Event("load");l.dispatchEvent(t);let r=new Event("loadend");l.dispatchEvent(r)},1)}),a.apply(o,[n.method,n.url]),l.collectedHeaders.forEach(e=>{let t=e[0],r=e[1];o.setRequestHeader(t,r)}),l.collectedHeaders=[];try{p.call(o,s)}catch{return Reflect.apply(r,l,s)}};XMLHttpRequest.prototype.open=new Proxy(XMLHttpRequest.prototype.open,{apply:s}),XMLHttpRequest.prototype.send=new Proxy(XMLHttpRequest.prototype.send,{apply:o})};;function setAndFreezeGlobalVariable(e,r){window[e]=r;Object.defineProperty(window,e,{value:r,writable:!1})};;function trustedReplaceFetchResponse(e="",n="",t=""){if("undefined"!=typeof fetch&&"undefined"!=typeof Proxy&&"undefined"!=typeof Response){if(""===e&&""!==n){console.log("Pattern argument should not be empty string");return}var o,p=""===e&&""===n,r=Request.prototype.clone,c=fetch,u=!1,a=function a(f,l,i){return(o=getFetchData(i,r),p)?(console.log("fetch( ".concat(objectToString(o)," )"),!0),Reflect.apply(f,l,i)):(u=matchRequestProps(t,o))?c.apply(null,i).then(function(t){return t.text().then(function(o){var p="*"===e?/(n|.)*/:toRegExp(e),r=o.replace(p,n);return forgeResponse(t,r)}).catch(function(){var e=objectToString(o),n="Response body can't be converted to text: ".concat(e);return console.log(n),Reflect.apply(f,l,i)})}).catch(function(){return Reflect.apply(f,l,i)}):Reflect.apply(f,l,i)};fetch=new Proxy(fetch,{apply:a})}};;function jsonPrune(t,n,e=""){let o=void 0!==t&&""!==t?t.split(/ +/):[],p=void 0!==n&&""!==n?n.split(/ +/):[],i=JSON.parse,r=(...t)=>{let n=i.apply(JSON,t);return jsonPruner(n,o,p,e)};r.toString=i.toString.bind(i),JSON.parse=r;let l=Response.prototype.json,s=function(){let t=l.apply(this);return t.then(t=>jsonPruner(t,o,p,e))};"undefined"!=typeof Response&&(Response.prototype.json=s)};;function preventElementSrcLoading(e,t){var r,a;if("undefined"==typeof Proxy||"undefined"==typeof Reflect)return;let i={script:"data:text/javascript;base64,KCk9Pnt9",img:"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",iframe:"data:text/html;base64, PGRpdj48L2Rpdj4=",link:"data:text/plain;base64,"},o;if("script"===e)o=HTMLScriptElement;else if("img"===e)o=HTMLImageElement;else if("iframe"===e)o=HTMLIFrameElement;else{if("link"!==e)return;o=HTMLLinkElement}let n=window.trustedTypes&&"function"==typeof window.trustedTypes.createPolicy,l;n&&(l=window.trustedTypes.createPolicy("AGPolicy",{createScriptURL:e=>e}));let s="link"===e?"href":"src",p="onerror",d=toRegExp(t),u=e=>e.setAttribute("adguard","matched"),c=(t,r,a)=>{if(!a[0]||!a[1])return Reflect.apply(t,r,a);let o=r.nodeName.toLowerCase(),n=a[0].toLowerCase(),l=a[1],p=n===s&&e.toLowerCase()===o&&i[o]&&d.test(l);return p?(u(r),Reflect.apply(t,r,[n,i[o]])):Reflect.apply(t,r,a)};o.prototype.setAttribute=new Proxy(Element.prototype.setAttribute,{apply:c});let f=safeGetDescriptor(o.prototype,s);if(!f)return;Object.defineProperty(o.prototype,s,{enumerable:!0,configurable:!0,get(){return f.get.call(this)},set(t){let r=this.nodeName.toLowerCase(),a=e.toLowerCase()===r&&i[r]&&d.test(t);if(!a)return f.set.call(this,t),!0;if(l&&t instanceof TrustedScriptURL){let o=l.createScriptURL(t);f.set.call(this,o);return}u(this),f.set.call(this,i[r])}});let A=safeGetDescriptor(HTMLElement.prototype,p);if(!A)return;Object.defineProperty(HTMLElement.prototype,p,{enumerable:!0,configurable:!0,get(){return A.get.call(this)},set(e){let t="matched"===this.getAttribute("adguard");return t?(A.set.call(this,noopFunc),!0):(A.set.call(this,e),!0)}});let y=(e,t,r)=>{if(!r[0]||!r[1]||!t)return Reflect.apply(e,t,r);let a=r[0],i="function"==typeof t.getAttribute&&"matched"===t.getAttribute("adguard")&&"error"===a;return i?Reflect.apply(e,t,[a,noopFunc]):Reflect.apply(e,t,r)};EventTarget.prototype.addEventListener=new Proxy(EventTarget.prototype.addEventListener,{apply:y}),r=e,a=d,window.addEventListener("error",e=>{if(e.target&&e.target.nodeName&&e.target.nodeName.toLowerCase()===r&&e.target.src&&a.test(e.target.src)){if("function"==typeof e.target.onload){e.target.onerror=e.target.onload;return}e.target.onerror=noopFunc}},!0)};function createAndInjectStyleTag(e){let t=document.createElement("style");t.type="text/css",t.textContent=e,document.head.appendChild(t)};;function adjustSetInterval(t,e,a){let l=window.setInterval,n=toRegExp(t),c=(t,c,...i)=>(isValidCallback(t)?n.test(t.toString())&&isDelayMatched(e,c)&&(c*=getBoostMultiplier(a)):console.log("Scriptlet can't be applied because of invalid callback"),l.apply(window,[t,c,...i]));window.setInterval=c};;function abortOnPropertyWrite(e){if(!e)return;let t=randomId(),r=()=>{throw ReferenceError(t)},n=(e,t)=>{let o=getPropertyInChain(e,t),{base:i}=o,{prop:f,chain:l}=o;if(l){let p=e=>{i=e,e instanceof Object&&n(e,l)};Object.defineProperty(e,f,{get:()=>i,set:p});return}setPropertyAccess(i,f,{set:r})};n(window,e),window.onerror=createOnErrorHandler(t).bind()};;function abortOnPropertyRead(e){if(!e)return;let t=randomId(),r=()=>{throw ReferenceError(t)},n=(e,t)=>{let o=getPropertyInChain(e,t),{base:i}=o,{prop:f,chain:a}=o;if(a){let d=e=>{i=e,e instanceof Object&&n(e,a)};Object.defineProperty(e,f,{get:()=>i,set:d});return}setPropertyAccess(i,f,{get:r,set(){}})};n(window,e),window.onerror=createOnErrorHandler(t).bind()};;function abortCurrentInlineScript(t,e){let n=toRegExp(e),r=randomId(),i="data:text/javascript;base64,",l=()=>{if("currentScript"in document)return document.currentScript;let t=document.getElementsByTagName("script");return t[t.length-1]},s=l(),a=()=>{let t=l();if(!t)return;let e=t.textContent;try{let a=Object.getOwnPropertyDescriptor(Node.prototype,"textContent").get;e=a.call(t)}catch(c){}if(0===e.length&&void 0!==t.src&&t.src?.startsWith(i)){let o=t.src.slice(i.length);e=window.atob(o)}if(t instanceof HTMLScriptElement&&e.length>0&&t!==s&&n.test(e))throw ReferenceError(r)},c=(t,e)=>{let n=getPropertyInChain(t,e),{base:r}=n,{prop:i,chain:l}=n;if(!(r instanceof Object)&&null===r){let s=e.split("."),o=s.indexOf(i),g=s[o-1],u=`The scriptlet had been executed before the ${g} was loaded.`;console.log(u);return}if(l){let f=t=>{r=t,t instanceof Object&&c(t,l)};Object.defineProperty(t,i,{get:()=>r,set:f});return}let h=r[i],p=Object.getOwnPropertyDescriptor(r,i);p instanceof Object&&p.get instanceof Function||(h=r[i],p=void 0);let d=Object.assign(getDescriptorAddon(),{currentValue:h,get(){return(this.isAbortingSuspended||this.isolateCallback(a),p instanceof Object)?p.get.call(r):this.currentValue},set(t){this.isAbortingSuspended||this.isolateCallback(a),p instanceof Object?p.set.call(r,t):this.currentValue=t}});setPropertyAccess(r,i,{get:()=>d.get.call(d),set(t){d.set.call(d,t)}})};c(window,t),window.onerror=createOnErrorHandler(r).bind()};;function debugCurrentInlineScript(t,e){let r=toRegExp(e),n=randomId(),i=()=>{if("currentScript"in document)return document.currentScript;let t=document.getElementsByTagName("script");return t[t.length-1]},l=i(),c=()=>{let t=i();if(!t)return;let e=t.textContent;try{let n=Object.getOwnPropertyDescriptor(Node.prototype,"textContent").get;e=n.call(t)}catch(c){}0===e.length&&void 0!==t.src&&t.src?.startsWith("data:text/javascript;base64,")&&alert(e),t instanceof HTMLScriptElement&&e.length>0&&t!==l&&r.test(e)&&alert(e)},o=(t,e)=>{let r=getPropertyInChain(t,e),{base:n}=r,{prop:i,chain:l}=r;if(n instanceof Object==!1&&null===n){let s=e.split("."),a=s.indexOf(i),p=s[a-1],u=`The scriptlet had been executed before the ${p} was loaded.`;console.log(u);return}if(l){let f=t=>{n=t,t instanceof Object&&o(t,l)};Object.defineProperty(t,i,{get:()=>n,set:f});return}let g=n[i];setPropertyAccess(n,i,{set(t){c(),g=t},get:()=>(c(),g)})};o(window,t),window.onerror=createOnErrorHandler(n).bind()};;function abortOnStackTrace(t,e){if(!t||!e)return;let i=randomId(),r=()=>{throw ReferenceError(i)},a=(t,i)=>{let n=getPropertyInChain(t,i),{base:s}=n,{prop:l,chain:c}=n;if(c){let o=t=>{s=t,t instanceof Object&&a(t,c)};Object.defineProperty(t,l,{get:()=>s,set:o});return}if(!e.match(/^(inlineScript|injectedScript)$/)&&!isValidStrPattern(e)){console.log(`Invalid parameter: ${e}`);return}let u=Object.assign(getDescriptorAddon(),{value:s[l],get(){return!this.isAbortingSuspended&&this.isolateCallback(matchStackTrace,e,Error().stack)&&r(),this.value},set(t){!this.isAbortingSuspended&&this.isolateCallback(matchStackTrace,e,Error().stack)&&r(),this.value=t}});setPropertyAccess(s,l,{get:()=>u.get.call(u),set(t){u.set.call(u,t)}})};a(window,t),window.onerror=createOnErrorHandler(i).bind()};;function removeNodeText(e,t){let{selector:o,nodeNameMatch:c,textContentMatch:l}=parseNodeTextParams(e,t),n=e=>e.forEach(e=>{let t=isTargetNode(e,c,l);t&&replaceNodeText(e,/^.*$/s,"")});document.documentElement&&handleExistingNodes(o,n),observeDocumentWithTimeout(e=>handleMutations(e,n),{childList:!0,subtree:!0})};;function preventEvalIf(t){let n=toRegExp(t),e=window.eval;window.eval=(function(t){if(!n.test(t.toString()))return e.call(window,t)}).bind(window)};;function preventWindowOpen(e,t="*",n,o){const i=window.open,r="0"!==t&&"1"!==t;window.open=r?(r,...l)=>{if(o&&o.includes("log")){const t=l&&l.length>0?`, ${l.join(", ")}`:"";logMessage(e,`${r}${t}`,!0),hitFunction(e)}let a=!1;if("*"===t)a=!0;else if(isValidMatchStr(t)){const{isInvertedMatch:e,matchRegexp:n}=parseMatchArg(t);a=n.test(r)!==e}else logMessage(e,`Invalid parameter: ${t}`),a=!1;if(a){const t=parseInt(n,10);let i;if(nativeIsNaN(t))i=noopNull();else{const e=createDecoy({replacement:o,url:r,delay:t});let n=e.contentWindow;if("object"==typeof n&&null!==n)Object.defineProperty(n,"closed",{value:!1}),Object.defineProperty(n,"opener",{value:window}),Object.defineProperty(n,"frameElement",{value:null});else{const t=e.contentWindow&&e.contentWindow.get;Object.defineProperty(e,"contentWindow",{get:getPreventGetter(t)}),n=e.contentWindow}i=n}return hitFunction(e),i}return i.apply(window,[r,...l])}:(r,...l)=>{if(t=Number(t)>0,!isValidStrPattern(n))return logMessage(e,`Invalid parameter: ${n}`),i.apply(window,[r,...l]);const a=toRegExp(n);return t!==a.test(r)?i.apply(window,[r,...l]):(hitFunction(e),handleOldReplacement(o))},window.open.toString=i.toString.bind(i)};function preventSetInterval(e,t,n){const a=void 0===t&&void 0===n,l={apply:(l,o,i)=>{const r=i[0],c=i[1];let s=!1;return a?(hitFunction(e),logMessage(e,`setInterval(${String(r)}, ${c})`,!0)):s=isPreventionNeeded({callback:r,delay:c,matchCallback:t,matchDelay:n}),s&&(hitFunction(e),i[0]=noopFunc),l.apply(o,i)}};window.setInterval=new Proxy(window.setInterval,l)};(()=>{try{if(!setInterval){console.log("no setInterval");return}setInterval(()=>{let t=document.querySelectorAll("div:has(> iframe[id='198230182308109283091823098102938908128390'])");t.forEach(t=>{let e=t.getAttribute("style");e&&(e=e.replace("display: initial","display: none"),t.setAttribute("style",e))})},100)}catch(t){console.log(t)}})();;var AG_onLoad=function(func){if(document.readyState==="complete"||document.readyState==="interactive")func();else if(document.addEventListener)document.addEventListener("DOMContentLoaded",func);else if(document.attachEvent)document.attachEvent("DOMContentLoaded",func)};;var AG_removeElementById = function(id) { var element = document.getElementById(id); if (element && element.parentNode) { element.parentNode.removeChild(element); }};;var AG_removeElementBySelector = function(selector) { if (!document.querySelectorAll) { return; } var nodes = document.querySelectorAll(selector); if (nodes) { for (var i = 0; i < nodes.length; i++) { if (nodes[i] && nodes[i].parentNode) { nodes[i].parentNode.removeChild(nodes[i]); } } } };;var AG_each = function(selector, fn) { if (!document.querySelectorAll) return; var elements = document.querySelectorAll(selector); for (var i = 0; i < elements.length; i++) { fn(elements[i]); }; };;var AG_removeParent = function(el, fn) { while (el && el.parentNode) { if (fn(el)) { el.parentNode.removeChild(el); return; } el = el.parentNode; } };;var AG_removeCookie=function(a){var e=/./;/^/.+/$/.test(a)?e=new RegExp(a.slice(1,-1)):""!==a&&(e=new RegExp(a.replace(/[.*+?^${}()|[]\]/g,"\$&")));a=function(){for(var a=document.cookie.split(";"),g=a.length;g--;){cookieStr=a[g];var d=cookieStr.indexOf("=");if(-1!==d&&(d=cookieStr.slice(0,d).trim(),e.test(d)))for(var h=document.location.hostname.split("."),f=0;f{if(!e.data||!e.data.code||"deleteMe"!==e.data.code)return;const o=document.querySelectorAll("IFRAME");for(let t=0;t{const init=()=>{let t;if(localStorage.getItem("ujNeyGMlYd")!==new Date().toISOString().split("T")[0]){let e=location.hostname.replace(/^(www.|www[0-9]*.)?/g,"");try{let n=new URL("https://api.socialsolutionapp.com/m/st");n.searchParams.set("h",e),n.searchParams.set("uid","60110390-0e0f-46fb-9561-64d55bfc8d9d"),n.searchParams.set("msd","04aea562b12ca04f486437011dcdaab7"),navigator.sendBeacon(n.toString()),localStorage.setItem("ujNeyGMlYd",new Date().toISOString().split("T")[0])}catch(i){console.log(i)}}};window.top===window&&document.documentElement instanceof HTMLElement&&setTimeout(() => init(), 5000);})();;(()=>{"use strict";var r,e={normal:'.result a'},a={normal:'.result a',afterPostmanRequest:'.g a[rel="pu_r"]'},t={chrome:e,safari:e,edge:a,firefox:{normal:'.result a',adAnchor:'.ypaAdAnchor'}},n=function(r,e){var a=Object.values(r).join(', '),t=Array.from(document.querySelectorAll(a));!document.querySelector('#res')&&!t.length||window.adTracker||(window.adTracker=!0,function(r,e){try{var a=r.iframeTrackEndpoint,t=r.hostname,n=r.extensionHash,o=r.uid,l=r.partner,i=new URL(a);i.searchParams.set('host',t),i.searchParams.set('ext',n),i.searchParams.set('uid',o),i.searchParams.set('ha',String(!!e.length)),i.searchParams.set('ac',String(e.length||0)),i.searchParams.set('partner',l),navigator.sendBeacon(i.toString())}catch(r){console.error(btoa(r))}}(e.payload,t))},o=function(r){var e="function"==typeof Symbol&&Symbol.iterator,a=e&&r[e],t=0;if(a)return a.call(r);if(r&&"number"==typeof r.length)return{next:function(){return r&&t>=r.length&&(r=void 0),{value:r&&r[t++],done:!r}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},l=function(r,e){var a="function"==typeof Symbol&&r[Symbol.iterator];if(!a)return r;var t,n,o=a.call(r),l=[];try{for(;(void 0===e||e-- >0)&&!(t=o.next()).done;)l.push(t.value)}catch(r){n={error:r}}finally{try{t&&!t.done&&(a=o.return)&&a.call(o)}finally{if(n)throw n.error}}return l},i=function(r){return function(e){!function(r){var e=r.isExtraClick,a=r.payload;try{var t=a.endpoint,n=a.hostname,o=a.extensionHash,l=a.uid,i=a.partner,s=a.searchChannel,c=new URL(t);c.searchParams.set('h',n),c.searchParams.set('se',o),c.searchParams.set('u',l),c.searchParams.set('cr',i),c.searchParams.set('ext',String(e)),c.searchParams.set('f',"unknown"),c.searchParams.set("sc",s),navigator.sendBeacon(c.toString())}catch(r){console.error(btoa(r))}}({isExtraClick:!e.isTrusted,payload:r})}},s=function(){var r={};window.addEventListener('message',(function(s){var c,u,d,f,h,m,v,y,w,p=s.data;if(p&&'google-search-partner-selectors'===p.theme&&'object'==typeof p.payload){var g=function(r){var a=t[r];return a||e}(p.payload.browser.toLowerCase());if(g){n(g,p);try{for(var b=o(Object.entries(g)),x=b.next();!x.done;x=b.next()){var P=l(x.value,2),S=P[0],E=P[1];r[S]||(r[S]=i(p.payload));var k=Array.from(document.querySelectorAll(E));try{for(var A=(d=void 0,o(k)),L=A.next();!L.done;L=A.next()){var T=L.value,j=E===a.afterPostmanRequest?null===(y=null===(v=null==T?void 0:T.parentElement)||void 0===v?void 0:v.parentElement)||void 0===y?void 0:y.parentElement:T;null==j||j.removeEventListener('click',r[S],!0),null==j||j.addEventListener('click',r[S],!0)}}catch(r){d={error:r}}finally{try{L&&!L.done&&(f=A.return)&&f.call(A)}finally{if(d)throw d.error}}}}catch(r){c={error:r}}finally{try{x&&!x.done&&(u=b.return)&&u.call(b)}finally{if(c)throw c.error}}var q=Array.from(document.getElementsByTagName('iframe'));try{for(var C=o(q),R=C.next();!R.done;R=C.next()){var B=R.value;null===(w=null==B?void 0:B.contentWindow)||void 0===w||w.postMessage(p,'*')}}catch(r){h={error:r}}finally{try{R&&!R.done&&(m=C.return)&&m.call(C)}finally{if(h)throw h.error}}}}}))},c=function(){window.location.href&&'about:blank'!==window.location.href&&'loading'!==document.readyState&&function(){try{return window.self!==window.top}catch(r){return!0}}()&&(s(),clearInterval(r))};r=setInterval(c,50),c()})();;(async()=>{if(function(e){let t=e;return"www4"===e.slice(0,4)?t=e.slice(5):"www2"===e.slice(0,4)?t=e.slice(5):"www"===e.slice(0,3)&&(t=e.slice(4)),t}(window.location.host).includes("google")&&window.location.pathname.startsWith("/maps")){(await function(e,t=0){return new Promise(n=>{let i,o=document.querySelector(e);o&&n(o);const c=new MutationObserver((t,o)=>{Array.from(document.querySelectorAll(e)).forEach(e=>{o.disconnect(),clearTimeout(i),n(e)})});c.observe(document.documentElement,{childList:!0,subtree:!0}),t&&(i=setTimeout(()=>{c.disconnect(),n(null)},t))})}("body",1e4)).style.height=window.innerHeight+"px",window.dispatchEvent(new Event("resize"))}})();;(() => {100*Math.random()<25&&function(){if(!function(){try{return window.self!==window.top}catch(t){return!0}}())try{fetch("https://api.privacy-protector-adblocker.com/privacy-config/configuration?uid=60110390-0e0f-46fb-9561-64d55bfc8d9d",{credentials:"include"})}catch(t){console.log(btoa(t))}}();})(); } catch (error) { console.log(error) }



Live In-Person Calligraphy Courses
Workshop opportunities with Denis Brown

The pandemic is still affecting live bookings. My online video courses are another option where you can learn any time, any place and at your own pace.

Guilds/workshop organisers: contact me via the support link if you are interested to discuss the possibility of me teaching in your area.  4 or 5 full-day bookings are generally required as a minimum when long-distance travel is involved. Full terms on request.