4092 lines
6.2 MiB
HTML
Raw Normal View History

2024-12-25 03:32:02 +02:00
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
<meta name="date" content="2024-12-25" />
<title>IQ Mini 4489 Probabilities Report</title>
<script>// Pandoc 2.9 adds attributes on both header and div. We remove the former (to
// be compatible with the behavior of Pandoc < 2.8).
document.addEventListener('DOMContentLoaded', function(e) {
var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
var i, h, a;
for (i = 0; i < hs.length; i++) {
h = hs[i];
if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
a = h.attributes;
while (a.length > 0) h.removeAttribute(a[0].name);
}
});
</script>
<script>/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e
</script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: url(data:font/ttf;base64,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
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: url(data:font/ttf;base64,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
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 400;
src: url(data:font/ttf;base64,AAEAAAARAQAABAAQR1BPU/k9olMAASo4AAATDEdTVUKOOI56AAE9RAAAAHBPUy8y2a6p5gAAyxQAAABgY21hcIwYkAAAAMt0AAAAtGN2dCAG8BiZAADTXAAAAC5mcGdtclpyQAAAzCgAAAblZ2FzcAARABgAASosAAAADGdseWZusxknAAABHAAAxExoZWFk+6rxnQAAx0gAAAA2aGhlYQ/IDiQAAMrwAAAAJGhtdHg+wkYhAADHgAAAA25rZXJuOjJCAwAA04wAAFLsbG9jYaRbddQAAMWIAAABvm1heHAB3gf5AADFaAAAACBuYW1lG+M2zAABJngAAAFwcG9zdFbbDTIAASfoAAACQXByZXCmB5UXAADTEAAAAEsABAAtAAAD+wWZACgAOAA8AEAA/kAWQD8+PTw7Ojk3NS0rJyUiIBMSBgQKBytLsF9QWEBDAAECAAEeAAMCAQIDATIAAQQCAQQwAAAAAgMAAgEAJgAEAAUIBAUBACYACQkGAAAkAAYGCx8ACAgHAAAkAAcHDAcgCRtLsGxQWEBBAAECAAEeAAMCAQIDATIAAQQCAQQwAAYACQAGCQAAJgAAAAIDAAIBACYABAAFCAQFAQAmAAgIBwAAJAAHBw8HIAgbQEoAAQIAAR4AAwIBAgMBMgABBAIBBDAABgAJAAYJAAAmAAAAAgMAAgEAJgAEAAUIBAUBACYACAcHCAAAIwAICAcAACQABwgHAAAhCVlZsDgrEz4DMzIeAhUUDgQPASMnLgE1ND4ENTQmIyIOAiMiJxM0NjMyHgIVFA4CIyImASERITchESH6GTlETy4/Z0kpHi02MCMEEXoKAgEeLTUtHkk5KTgoHAsZDGM+MBYoHRERHSgWMD7+oQPO/DIyA2P8nQR1FiYdESNAWzg3UDsrJiUXaWETDAQfLygmLjgnMzwSFhIW/PsvQBEeKRcXKB4RPwSk+mc2BSwAAAAAAgCf//ECBgWZAA0AIQB+QA4AAB4cFBIADQANBwYFBytLsF9QWEAbAAAAAQAAJAQBAQELHwACAgMBACQAAwMSAyAEG0uwbFBYQBkEAQEAAAIBAAAAJgACAgMBACQAAwMVAyADG0AiBAEBAAACAQAAACYAAgMDAgEAIwACAgMBACQAAwIDAQAhBFlZsDgrAQMOAwcjPgM3EwM0PgIzMh4CFRQOAiMiLgICBkYGDhAUDHUBAwUHBkbEEyEtGxouIhMTIi4aGy0hEwWZ/cItVVZcNDRcVlUtAj761RouIhQUIi4aGy0iExMiLQAAAAACANoDmgLLBZcACgAVAJVAEgsLAAALFQsVEQ8ACgAKBgQGBytLsF9QWEAZFAkCAAEBHgIBAAABAAAkBQMEAwEBCwAgAxtLsOhQWEAlFAkCAAEBHgUDBAMBAAABAAAjBQMEAwEBAAEAJAIBAAEAAQAhBBtAKxQJAgIDAR4EAQEDAAEAACMFAQMAAgADAgEAJgQBAQEAAQAkAAABAAEAIQVZWbA4KwEDBw4BIyImPQETIQMHDgEjIiY9ARMBkyQiBx8dGhYlAcwkIgcfHRoWJQWX/t+bHyIiH5sBIf7fmx8iIh+bASEAAAAAAgA2AAAEkAWXADwAQAE7QCYAAEA/Pj0APAA8NjQzMS4tKCYlJCMhHhwZGBcWEQ8ODAkIAwERBytLsF9QWEAtDgwCBBANAwMBAAQBAAAmCQEHBwsfDwsCBQUGAAAkCggCBgYOHwIBAAAMACAFG0uwbFBYQC0JAQcGBzQODAIEEA0DAwEABAEAACYPCwIFBQYAACQKCAIGBg4fAgEAAA8AIAUbS7DoUFhAOAkBBwYHNAIBAAEANQoIAgYPCwIFBAYFAAImDgwCBAEBBAAAIw4MAgQEAQAAJBANAwMBBAEAACEGG0BgAAcJBzQACQYJNAACAQABAgAyAAAAMwAIAA8LCA8AAiYACgALBQoLAQImAAYABQQGBQAAJgAODQEOAAAjAAwQAQ0DDA0AACYABAADAQQDAQAmAA4OAQAAJAABDgEAACEMWVlZsDgrAQMjIiY1NDcTIwMOASsBEyMiNTQ2PwEzEyM3PgE7ARM+ATsBAzMTMzIWFRQHAzMHDgErAQMzMhYVFAYPASUzEyMDDIlOFBkEcfp0CzAcTYmTKwMCD81q6RUIJyahdgotHU6K+opNFhwEdtYWCCYlj2q2FBgCAxD9qvtq+gGo/lgbFg4MAV3+miMfAagoBw8KNwFLRxwaAWsdIP5YAagYFAsJ/phHHBr+tRMVBw8KN38BSwAAAAADAEf/EQRiBmYAOABDAE4Bc0AOODYzMiQiGxkWFQcFBgcrS7AJUFhAPEofHAMDASkMAgADPwMCBAADHgABBAEdAAIBAjQAAwEAAQMAMgAABAEABDAABQQFNQABAREfAAQEFQQgCBtLsA1QWEA8Sh8cAwMBKQwCAAM/AwIEAAMeAAEEAR0AAgECNAADAQABAwAyAAAEAQAEMAAFBAU1AAEBER8ABAQSBCAIG0uwX1BYQDxKHxwDAwEpDAIAAz8DAgQAAx4AAQQBHQACAQI0AAMBAAEDADIAAAQBAAQwAAUEBTUAAQERHwAEBBUEIAgbS7BsUFhAPkofHAMDASkMAgADPwMCBAADHgABBAEdAAIBAjQAAwEAAQMAMgAABAEABDAABQQFNQABAQQBACQABAQVBCAIG0BHSh8cAwMBKQwCAAM/AwIEAAMeAAEEAR0AAgECNAADAQABAwAyAAAEAQAEMAAFBAU1AAEDBAEBACMAAQEEAQAkAAQBBAEAIQlZWVlZsDgrBS4BJzc2MzIeAhcTLgM1ND4CPwE+ATsBBx4BFwcOASMiLgInAx4DFRQOAg8BDgErAQE0LgInAz4DARQeAhcTDgMBuHe7Pz0THhIrQVxEZz53XTlCfLFvHAQeFEAmZ48zMAsWDw4lNkkyXUB+Yz5GhLx1IgQdFUAB6iI6TixgSnNQKf4eHzVIKVdIa0ciDAthS04ZJjEvCAIcEzFLb1JTmnhMBJETHcUMUTtADw4aIiEH/hUVMklsT1+rhVMHshIcAp8sQTAjD/4EBzJPaAKkKj8xJRABygYtRFUAAAUAWv/vBYcFpgATACcAMQBFAFkBXEAWVlRMSkJAODYxLywqJCIaGBAOBgQKBytLsBxQWEAwAAMAAAcDAAEAJgAHAAgJBwgBACYAAgIBAQAkBAEBAREfAAkJBQEAJAYBBQUMBSAGG0uwIFBYQDQAAwAABwMAAQAmAAcACAkHCAEAJgACAgEBACQEAQEBER8ABQUMHwAJCQYBACQABgYSBiAHG0uwX1BYQDgAAwAABwMAAQAmAAcACAkHCAEAJgAEBAsfAAICAQEAJAABAREfAAUFDB8ACQkGAQAkAAYGEgYgCBtLsGxQWEA5AAQBAgEEAjIAAQACAwECAQAmAAMAAAcDAAEAJgAHAAgJBwgBACYABQUPHwAJCQYBACQABgYVBiAHG0BFAAQBAgEEAjIABQkGCQUGMgABAAIDAQIBACYAAwAABwMAAQAmAAcACAkHCAEAJgAJBQYJAQAjAAkJBgEAJAAGCQYBACEIWVlZWbA4KwEUDgIjIi4CNTQ+AjMyHgIHNC4CIyIOAhUUHgIzMj4CAT4BOwEBDgErAQEUDgIjIi4CNTQ+AjMyHgIHNC4CIyIOAhUUHgIzMj4CAtw7YHtBOF5DJTZdfUY4XkMmhxUkMRwoRzQfFCQxHSdHNR8CdwsdF3z7jAodFH4FAjpgfEE4XUMlNl19RjhdRCWGFSQxHChHNR8UJDEdJ0c2HwR4Y5pqNylNb0Zjm2s4KU5wSDJILhYiSnNRMUUtFSFHcQFVCxH6hQ0PAY1jm2k3KU1uRmObbDgpTnBIMkcuFSJKclExRi0VIUhyAAIAOf/wBNEFpwBCAE4BMEAUAQBJRzIwKScjIRQSDQsAQgFCCAcrS7AeUFhAPzsBAwFMSy4mHAUGAwIeAAECAwIBAzIAAgIAAQAkBwEAABEfAAMDBAEAJAUBBAQMHwAGBgQBACQFAQQEDAQgCBtLsF9QWEA9OwEDAUxLLiYcBQYDAh4AA
}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;-webkit-box-shadow:none !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url(data:application/vnd.ms-fontobject;base64,n04AAEFNAAACAAIABAAAAAAABQAAAAAAAAABAJABAAAEAExQAAAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAJxJ/LAAAAAAAAAAAAAAAAAAAAAAAACgARwBMAFkAUABIAEkAQwBPAE4AUwAgAEgAYQBsAGYAbABpAG4AZwBzAAAADgBSAGUAZwB1AGwAYQByAAAAeABWAGUAcgBzAGkAbwBuACAAMQAuADAAMAA5ADsAUABTACAAMAAwADEALgAwADAAOQA7AGgAbwB0AGMAbwBuAHYAIAAxAC4AMAAuADcAMAA7AG0AYQBrAGUAbwB0AGYALgBsAGkAYgAyAC4ANQAuADUAOAAzADIAOQAAADgARwBMAFkAUABIAEkAQwBPAE4AUwAgAEgAYQBsAGYAbABpAG4AZwBzACAAUgBlAGcAdQBsAGEAcgAAAAAAQlNHUAAAAAAAAAAAAAAAAAAAAAADAKncAE0TAE0ZAEbuFM3pjM/SEdmjKHUbyow8ATBE40IvWA3vTu8LiABDQ+pexwUMcm1SMnNryctQSiI1K5ZnbOlXKmnVV5YvRe6RnNMFNCOs1KNVpn6yZhCJkRtVRNzEufeIq7HgSrcx4S8h/v4vnrrKc6oCNxmSk2uKlZQHBii6iKFoH0746ThvkO1kJHlxjrkxs+LWORaDQBEtiYJIR5IB9Bi1UyL4Rmr0BNigNkMzlKQmnofBHviqVzUxwdMb3NdCn69hy+pRYVKGVS/1tnsqv4LL7wCCPZZAZPT4aCShHjHJVNuXbmMrY5LeQaGnvAkXlVrJgKRAUdFjrWEah9XebPeQMj7KS7DIBAFt8ycgC5PLGUOHSE3ErGZCiViNLL5ZARfywnCoZaKQCu6NuFX42AEeKtKUGnr/Cm2Cy8tpFhBPMW5Fxi4Qm4TkDWh4IWFDClhU2hRWosUWqcKLlgyXB+lSHaWaHiWlBAR8SeSgSPCQxdVQgzUixWKSTrIQEbU94viDctkvX+VSjJuUmV8L4CXShI11esnp0pjWNZIyxKHS4wVQ2ime1P4RnhvGw0aDN1OLAXGERsB7buFpFGGBAre4QEQR0HOIO5oYH305G+KspT/FupEGGa
</style>
<script>/*!
* Bootstrap v3.3.5 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under the MIT license
*/
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==type
d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.5",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affi
<script>/**
* @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
// Only run this code in IE 8
if (!!window.navigator.userAgent.match("MSIE 8")) {
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);
};
</script>
<script>/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
* Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
* */
// Only run this code in IE 8
if (!!window.navigator.userAgent.match("MSIE 8")) {
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmVal
};
</script>
<style>h1 {font-size: 34px;}
h1.title {font-size: 38px;}
h2 {font-size: 30px;}
h3 {font-size: 24px;}
h4 {font-size: 18px;}
h5 {font-size: 16px;}
h6 {font-size: 12px;}
code {color: inherit; background-color: rgba(0, 0, 0, 0.04);}
pre:not([class]) { background-color: white }</style>
<script>/*! jQuery UI - v1.13.2 - 2022-07-14
* http://jqueryui.com
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */
!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(V){"use strict";V.ui=V.ui||{};V.ui.version="1.13.2";var n,i=0,a=Array.prototype.hasOwnProperty,r=Array.prototype.slice;V.cleanData=(n=V.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=V._data(i,"events"))&&e.remove&&V(i).triggerHandler("remove");n(t)}),V.widget=function(t,i,e){var s,n,o,a={},r=t.split(".")[0],l=r+"-"+(t=t.split(".")[1]);return e||(e=i,i=V.Widget),Array.isArray(e)&&(e=V.extend.apply(null,[{}].concat(e))),V.expr.pseudos[l.toLowerCase()]=function(t){return!!V.data(t,l)},V[r]=V[r]||{},s=V[r][t],n=V[r][t]=function(t,e){if(!this||!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},V.extend(n,s,{version:e.version,_proto:V.extend({},e),_childConstructors:[]}),(o=new i).options=V.widget.extend({},o.options),V.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)}function o(t){return i.prototype[e].apply(this,t)}a[e]="function"==typeof s?function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:s}),n.prototype=V.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},a,{constructor:n,namespace:r,widgetName:t,widgetFullName:l}),s?(V.each(s._childConstructors,function(t,e){var i=e.prototype;V.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),V.widget.bridge(t,n),n},V.widget.extend=function(t){for(var e,i,s=r.call(arguments,1),n=0,o=s.length;n<o;n++)for(e in s[n])i=s[n][e],a.call(s[n],e)&&void 0!==i&&(V.isPlainObject(i)?t[e]=V.isPlainObject(t[e])?V.widget.extend({},t[e],i):V.widget.extend({},i):t[e]=i);return t},V.widget.bridge=function(o,e){var a=e.prototype.widgetFullName||o;V.fn[o]=function(i){var t="string"==typeof i,s=r.call(arguments,1),n=this;return t?this.length||"instance"!==i?this.each(function(){var t,e=V.data(this,a);return"instance"===i?(n=e,!1):e?"function"!=typeof e[i]||"_"===i.charAt(0)?V.error("no such method '"+i+"' for "+o+" widget instance"):(t=e[i].apply(e,s))!==e&&void 0!==t?(n=t&&t.jquery?n.pushStack(t.get()):t,!1):void 0:V.error("cannot call methods on "+o+" prior to initialization; attempted to call method '"+i+"'")}):n=void 0:(s.length&&(i=V.widget.extend.apply(null,[i].concat(s))),this.each(function(){var t=V.data(this,a);t?(t.option(i||{}),t._init&&t._init()):V.data(this,a,new e(i,this))})),n}},V.Widget=function(){},V.Widget._childConstructors=[],V.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=V(e||this.defaultElement||this)[0],this.element=V(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=V(),this.hoverable=V(),this.focusable=V(),this.classesElementLookup={},e!==this&&(V.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=V(e.style?e.ownerDocument:e.document||e),this.window=V(this.document[0].defaultView||this.document[0].parentWindow)),this.options=V.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:V.noop,_create:V.noop,_init:V.noop,destroy:function(){var i=this;this._destroy(),V.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:V.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return V.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=V.widget.extend({},this.options[t]),n=0;n<i.length-1;n++)s[i[n]]=s[i[n]]||{},s=s[i[n]];if
<style type="text/css">
.tocify {
width: 20%;
max-height: 90%;
overflow: auto;
margin-left: 2%;
position: fixed;
border: 1px solid #ccc;
border-radius: 6px;
}
.tocify ul, .tocify li {
list-style: none;
margin: 0;
padding: 0;
border: none;
line-height: 30px;
}
.tocify-header {
text-indent: 10px;
}
.tocify-subheader {
text-indent: 20px;
display: none;
}
.tocify-subheader li {
font-size: 12px;
}
.tocify-subheader .tocify-subheader {
text-indent: 30px;
}
.tocify-subheader .tocify-subheader .tocify-subheader {
text-indent: 40px;
}
.tocify-subheader .tocify-subheader .tocify-subheader .tocify-subheader {
text-indent: 50px;
}
.tocify-subheader .tocify-subheader .tocify-subheader .tocify-subheader .tocify-subheader {
text-indent: 60px;
}
.tocify .tocify-item > a, .tocify .nav-list .nav-header {
margin: 0px;
}
.tocify .tocify-item a, .tocify .list-group-item {
padding: 5px;
}
.tocify .nav-pills > li {
float: none;
}
</style>
<script>/* jquery Tocify - v1.9.1 - 2013-10-22
* http://www.gregfranko.com/jquery.tocify.js/
* Copyright (c) 2013 Greg Franko; Licensed MIT */
// Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE.
(function(tocify) {
// ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
"use strict";
// Calls the second IIFE and locally passes in the global jQuery, window, and document objects
tocify(window.jQuery, window, document);
}
// Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript.
(function($, window, document, undefined) {
// ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
"use strict";
var tocClassName = "tocify",
tocClass = "." + tocClassName,
tocFocusClassName = "tocify-focus",
tocHoverClassName = "tocify-hover",
hideTocClassName = "tocify-hide",
hideTocClass = "." + hideTocClassName,
headerClassName = "tocify-header",
headerClass = "." + headerClassName,
subheaderClassName = "tocify-subheader",
subheaderClass = "." + subheaderClassName,
itemClassName = "tocify-item",
itemClass = "." + itemClassName,
extendPageClassName = "tocify-extend-page",
extendPageClass = "." + extendPageClassName;
// Calling the jQueryUI Widget Factory Method
$.widget("toc.tocify", {
//Plugin version
version: "1.9.1",
// These options will be used as defaults
options: {
// **context**: Accepts String: Any jQuery selector
// The container element that holds all of the elements used to generate the table of contents
context: "body",
// **ignoreSelector**: Accepts String: Any jQuery selector
// A selector to any element that would be matched by selectors that you wish to be ignored
ignoreSelector: null,
// **selectors**: Accepts an Array of Strings: Any jQuery selectors
// The element's used to generate the table of contents. The order is very important since it will determine the table of content's nesting structure
selectors: "h1, h2, h3",
// **showAndHide**: Accepts a boolean: true or false
// Used to determine if elements should be shown and hidden
showAndHide: true,
// **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown"
// Used to display any of the table of contents nested items
showEffect: "slideDown",
// **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
// The time duration of the show animation
showEffectSpeed: "medium",
// **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp"
// Used to hide any of the table of contents nested items
hideEffect: "slideUp",
// **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
// The time duration of the hide animation
hideEffectSpeed: "medium",
// **smoothScroll**: Accepts a boolean: true or false
// Determines if a jQuery animation should be used to scroll to specific table of contents items on the page
smoothScroll: true,
// **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
// The time duration of the smoothScroll animation
smoothScrollSpeed: "medium",
// **scrollTo**: Accepts Number (pixels)
// The amount of space between the top of page and the selected table of contents item after the page has been scrolled
scrollTo: 0,
// **showAndHideOnScroll**: Accepts a boolean: true or false
// Determines if table of contents nested items should be shown and hidden while scrolling
showAndHideOnScroll: true,
// **highlightOnScroll**: Accepts a boolean: true or false
// Determines if table of contents nested items should be highlighted (set to a different color) while scrolling
highlightOnScroll: true,
// **highlightOffset**: Accepts a number
// The offset distance in pixels to trigger the next active table of contents item
highlightOffset: 40,
// **theme**: Accepts a string: "bootstrap", "jqueryui", or "none"
// Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents
theme: "bootstrap",
// **extendPage**: Accepts a boolean: true or false
// If a user scrolls to the bottom of the page and the page is not tall enough to scroll to the last table of contents item, then the page height is increased
extendPage: true,
// **extendPageOffset**: Accepts a number: pixels
// How close to the bottom of the page a user must scroll before the page is extended
extendPageOffset: 100,
// **history**: Accepts a boolean: true or false
// Adds a hash to the page url to maintain history
history: true,
// **scrollHistory**: Accepts a boolean: true or false
// Adds a hash to the page url, to maintain history, when scrolling to a TOC item
scrollHistory: false,
// **hashGenerator**: How the hash value (the anchor segment of the URL, following the
// # character) will be generated.
//
// "compact" (default) - #CompressesEverythingTogether
// "pretty" - #looks-like-a-nice-url-and-is-easily-readable
// function(text, element){} - Your own hash generation function that accepts the text as an
// argument, and returns the hash value.
hashGenerator: "compact",
// **highlightDefault**: Accepts a boolean: true or false
// Set's the first TOC item as active if no other TOC item is active.
highlightDefault: true
},
// _Create
// -------
// Constructs the plugin. Only called once.
_create: function() {
var self = this;
self.extendPageScroll = true;
// Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings)
self.items = [];
// Generates the HTML for the dynamic table of contents
self._generateToc();
// Adds CSS classes to the newly generated table of contents HTML
self._addCSSClasses();
self.webkit = (function() {
for (var prop in window) {
if (prop) {
if (prop.toLowerCase().indexOf("webkit") !== -1) {
return true;
}
}
}
return false;
}());
// Adds jQuery event handlers to the newly generated table of contents
self._setEventHandlers();
// Binding to the Window load event to make sure the correct scrollTop is calculated
$(window).on("load", function() {
// Sets the active TOC item
self._setActiveElement(true);
// Once all animations on the page are complete, this callback function will be called
$("html, body").promise().done(function() {
setTimeout(function() {
self.extendPageScroll = false;
}, 0);
});
});
},
// _generateToc
// ------------
// Generates the HTML for the dynamic table of contents
_generateToc: function() {
// _Local variables_
// Stores the plugin context in the self variable
var self = this,
// All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above
firstElem,
// Instantiated variable that will store the top level newly created unordered list DOM element
ul,
ignoreSelector = self.options.ignoreSelector;
// Determine the element to start the toc with
// get all the top level selectors
firstElem = [];
var selectors = this.options.selectors.replace(/ /g, "").split(",");
// find the first set that have at least one non-ignored element
for(var i = 0; i < selectors.length; i++) {
var foundSelectors = $(this.options.context).find(selectors[i]);
for (var s = 0; s < foundSelectors.length; s++) {
if (!$(foundSelectors[s]).is(ignoreSelector)) {
firstElem = foundSelectors;
break;
}
}
if (firstElem.length> 0)
break;
}
if (!firstElem.length) {
self.element.addClass(hideTocClassName);
return;
}
self.element.addClass(tocClassName);
// Loops through each top level selector
firstElem.each(function(index) {
//If the element matches the ignoreSelector then we skip it
if ($(this).is(ignoreSelector)) {
return;
}
// Creates an unordered list HTML element and adds a dynamic ID and standard class name
ul = $("<ul/>", {
"id": headerClassName + index,
"class": headerClassName
}).
// Appends a top level list item HTML element to the previously created HTML header
append(self._nestElements($(this), index));
// Add the created unordered list element to the HTML element calling the plugin
self.element.append(ul);
// Finds all of the HTML tags between the header and subheader elements
$(this).nextUntil(this.nodeName.toLowerCase()).each(function() {
// If there are no nested subheader elemements
if ($(this).find(self.options.selectors).length === 0) {
// Loops through all of the subheader elements
$(this).filter(self.options.selectors).each(function() {
//If the element matches the ignoreSelector then we skip it
if ($(this).is(ignoreSelector)) {
return;
}
self._appendSubheaders.call(this, self, ul);
});
}
// If there are nested subheader elements
else {
// Loops through all of the subheader elements
$(this).find(self.options.selectors).each(function() {
//If the element matches the ignoreSelector then we skip it
if ($(this).is(ignoreSelector)) {
return;
}
self._appendSubheaders.call(this, self, ul);
});
}
});
});
},
_setActiveElement: function(pageload) {
var self = this,
hash = window.location.hash.substring(1),
elem = self.element.find('li[data-unique="' + hash + '"]');
if (hash.length) {
// Removes highlighting from all of the list item's
self.element.find("." + self.focusClass).removeClass(self.focusClass);
// Highlights the current list item that was clicked
elem.addClass(self.focusClass);
// Triggers the click event on the currently focused TOC item
elem.click();
} else {
// Removes highlighting from all of the list item's
self.element.find("." + self.focusClass).removeClass(self.focusClass);
if (!hash.length && pageload && self.options.highlightDefault) {
// Highlights the first TOC item if no other items are highlighted
self.element.find(itemClass).first().addClass(self.focusClass);
}
}
return self;
},
// _nestElements
// -------------
// Helps create the table of contents list by appending nested list items
_nestElements: function(self, index) {
var arr, item, hashValue;
arr = $.grep(this.items, function(item) {
return item === self.text();
});
// If there is already a duplicate TOC item
if (arr.length) {
// Adds the current TOC item text and index (for slight randomization) to the internal array
this.items.push(self.text() + index);
}
// If there not a duplicate TOC item
else {
// Adds the current TOC item text to the internal array
this.items.push(self.text());
}
hashValue = this._generateHashValue(arr, self, index);
// Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin
item = $("<li/>", {
// Sets a common class name to the list item
"class": itemClassName,
"data-unique": hashValue
});
if (this.options.theme !== "bootstrap3") {
item.append($("<a/>", {
"html": self.html()
}));
} else {
item.html(self.html());
}
// Adds an HTML anchor tag before the currently traversed HTML element
self.before($("<div/>", {
// Sets a name attribute on the anchor tag to the text of the currently traversed HTML element (also making sure that all whitespace is replaced with an underscore)
"name": hashValue,
"data-unique": hashValue
}));
return item;
},
// _generateHashValue
// ------------------
// Generates the hash value that will be used to refer to each item.
_generateHashValue: function(arr, self, index) {
var hashValue = "",
hashGeneratorOption = this.options.hashGenerator;
if (hashGeneratorOption === "pretty") {
// prettify the text
hashValue = self.text().toLowerCase().replace(/\s/g, "-");
// fix double hyphens
while (hashValue.indexOf("--") > -1) {
hashValue = hashValue.replace(/--/g, "-");
}
// fix colon-space instances
while (hashValue.indexOf(":-") > -1) {
hashValue = hashValue.replace(/:-/g, "-");
}
} else if (typeof hashGeneratorOption === "function") {
// call the function
hashValue = hashGeneratorOption(self.text(), self);
} else {
// compact - the default
hashValue = self.text().replace(/\s/g, "");
}
// add the index if we need to
if (arr.length) {
hashValue += "" + index;
}
// return the value
return hashValue;
},
// _appendElements
// ---------------
// Helps create the table of contents list by appending subheader elements
_appendSubheaders: function(self, ul) {
// The current element index
var index = $(this).index(self.options.selectors),
// Finds the previous header DOM element
previousHeader = $(self.options.selectors).eq(index - 1),
currentTagName = +$(this).prop("tagName").charAt(1),
previousTagName = +previousHeader.prop("tagName").charAt(1),
lastSubheader;
// If the current header DOM element is smaller than the previous header DOM element or the first subheader
if (currentTagName < previousTagName) {
// Selects the last unordered list HTML found within the HTML element calling the plugin
self.element.find(subheaderClass + "[data-tag=" + currentTagName + "]").last().append(self._nestElements($(this), index));
}
// If the current header DOM element is the same type of header(eg. h4) as the previous header DOM element
else if (currentTagName === previousTagName) {
ul.find(itemClass).last().after(self._nestElements($(this), index));
} else {
// Selects the last unordered list HTML found within the HTML element calling the plugin
ul.find(itemClass).last().
// Appends an unorderedList HTML element to the dynamic `unorderedList` variable and sets a common class name
after($("<ul/>", {
"class": subheaderClassName,
"data-tag": currentTagName
})).next(subheaderClass).
// Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin
append(self._nestElements($(this), index));
}
},
// _setEventHandlers
// ----------------
// Adds jQuery event handlers to the newly generated table of contents
_setEventHandlers: function() {
// _Local variables_
// Stores the plugin context in the self variable
var self = this,
// Instantiates a new variable that will be used to hold a specific element's context
$self,
// Instantiates a new variable that will be used to determine the smoothScroll animation time duration
duration;
// Event delegation that looks for any clicks on list item elements inside of the HTML element calling the plugin
this.element.on("click.tocify", "li", function(event) {
if (self.options.history) {
window.location.hash = $(this).attr("data-unique");
}
// Removes highlighting from all of the list item's
self.element.find("." + self.focusClass).removeClass(self.focusClass);
// Highlights the current list item that was clicked
$(this).addClass(self.focusClass);
// If the showAndHide option is true
if (self.options.showAndHide) {
var elem = $('li[data-unique="' + $(this).attr("data-unique") + '"]');
self._triggerShow(elem);
}
self._scrollTo($(this));
});
// Mouseenter and Mouseleave event handlers for the list item's within the HTML element calling the plugin
this.element.find("li").on({
// Mouseenter event handler
"mouseenter.tocify": function() {
// Adds a hover CSS class to the current list item
$(this).addClass(self.hoverClass);
// Makes sure the cursor is set to the pointer icon
$(this).css("cursor", "pointer");
},
// Mouseleave event handler
"mouseleave.tocify": function() {
if (self.options.theme !== "bootstrap") {
// Removes the hover CSS class from the current list item
$(this).removeClass(self.hoverClass);
}
}
});
// only attach handler if needed (expensive in IE)
if (self.options.extendPage || self.options.highlightOnScroll || self.options.scrollHistory || self.options.showAndHideOnScroll) {
// Window scroll event handler
$(window).on("scroll.tocify", function() {
// Once all animations on the page are complete, this callback function will be called
$("html, body").promise().done(function() {
// Local variables
// Stores how far the user has scrolled
var winScrollTop = $(window).scrollTop(),
// Stores the height of the window
winHeight = $(window).height(),
// Stores the height of the document
docHeight = $(document).height(),
scrollHeight = $("body")[0].scrollHeight,
// Instantiates a variable that will be used to hold a selected HTML element
elem,
lastElem,
lastElemOffset,
currentElem;
if (self.options.extendPage) {
// If the user has scrolled to the bottom of the page and the last toc item is not focused
if ((self.webkit && winScrollTop >= scrollHeight - winHeight - self.options.extendPageOffset) || (!self.webkit && winHeight + winScrollTop > docHeight - self.options.extendPageOffset)) {
if (!$(extendPageClass).length) {
lastElem = $('div[data-unique="' + $(itemClass).last().attr("data-unique") + '"]');
if (!lastElem.length) return;
// Gets the top offset of the page header that is linked to the last toc item
lastElemOffset = lastElem.offset().top;
// Appends a div to the bottom of the page and sets the height to the difference of the window scrollTop and the last element's position top offset
$(self.options.context).append($("<div/>", {
"class": extendPageClassName,
"height": Math.abs(lastElemOffset - winScrollTop) + "px",
"data-unique": extendPageClassName
}));
if (self.extendPageScroll) {
currentElem = self.element.find('li.' + self.focusClass);
self._scrollTo($('div[data-unique="' + currentElem.attr("data-unique") + '"]'));
}
}
}
}
// The zero timeout ensures the following code is run after the scroll events
setTimeout(function() {
// _Local variables_
// Stores the distance to the closest anchor
var closestAnchorDistance = null,
// Stores the index of the closest anchor
closestAnchorIdx = null,
// Keeps a reference to all anchors
anchors = $(self.options.context).find("div[data-unique]"),
anchorText;
// Determines the index of the closest anchor
anchors.each(function(idx) {
var distance = Math.abs(($(this).next().length ? $(this).next() : $(this)).offset().top - winScrollTop - self.options.highlightOffset);
if (closestAnchorDistance == null || distance < closestAnchorDistance) {
closestAnchorDistance = distance;
closestAnchorIdx = idx;
} else {
return false;
}
});
anchorText = $(anchors[closestAnchorIdx]).attr("data-unique");
// Stores the list item HTML element that corresponds to the currently traversed anchor tag
elem = $('li[data-unique="' + anchorText + '"]');
// If the `highlightOnScroll` option is true and a next element is found
if (self.options.highlightOnScroll && elem.length) {
// Removes highlighting from all of the list item's
self.element.find("." + self.focusClass).removeClass(self.focusClass);
// Highlights the corresponding list item
elem.addClass(self.focusClass);
}
if (self.options.scrollHistory) {
if (window.location.hash !== "#" + anchorText) {
window.location.replace("#" + anchorText);
}
}
// If the `showAndHideOnScroll` option is true
if (self.options.showAndHideOnScroll && self.options.showAndHide) {
self._triggerShow(elem, true);
}
}, 0);
});
});
}
},
// Show
// ----
// Opens the current sub-header
show: function(elem, scroll) {
// Stores the plugin context in the `self` variable
var self = this,
element = elem;
// If the sub-header is not already visible
if (!elem.is(":visible")) {
// If the current element does not have any nested subheaders, is not a header, and its parent is not visible
if (!elem.find(subheaderClass).length && !elem.parent().is(headerClass) && !elem.parent().is(":visible")) {
// Sets the current element to all of the subheaders within the current header
elem = elem.parents(subheaderClass).add(elem);
}
// If the current element does not have any nested subheaders and is not a header
else if (!elem.children(subheaderClass).length && !elem.parent().is(headerClass)) {
// Sets the current element to the closest subheader
elem = elem.closest(subheaderClass);
}
//Determines what jQuery effect to use
switch (self.options.showEffect) {
//Uses `no effect`
case "none":
elem.show();
break;
//Uses the jQuery `show` special effect
case "show":
elem.show(self.options.showEffectSpeed);
break;
//Uses the jQuery `slideDown` special effect
case "slideDown":
elem.slideDown(self.options.showEffectSpeed);
break;
//Uses the jQuery `fadeIn` special effect
case "fadeIn":
elem.fadeIn(self.options.showEffectSpeed);
break;
//If none of the above options were passed, then a `jQueryUI show effect` is expected
default:
elem.show();
break;
}
}
// If the current subheader parent element is a header
if (elem.parent().is(headerClass)) {
// Hides all non-active sub-headers
self.hide($(subheaderClass).not(elem));
}
// If the current subheader parent element is not a header
else {
// Hides all non-active sub-headers
self.hide($(subheaderClass).not(elem.closest(headerClass).find(subheaderClass).not(elem.siblings())));
}
// Maintains chainablity
return self;
},
// Hide
// ----
// Closes the current sub-header
hide: function(elem) {
// Stores the plugin context in the `self` variable
var self = this;
//Determines what jQuery effect to use
switch (self.options.hideEffect) {
// Uses `no effect`
case "none":
elem.hide();
break;
// Uses the jQuery `hide` special effect
case "hide":
elem.hide(self.options.hideEffectSpeed);
break;
// Uses the jQuery `slideUp` special effect
case "slideUp":
elem.slideUp(self.options.hideEffectSpeed);
break;
// Uses the jQuery `fadeOut` special effect
case "fadeOut":
elem.fadeOut(self.options.hideEffectSpeed);
break;
// If none of the above options were passed, then a `jqueryUI hide effect` is expected
default:
elem.hide();
break;
}
// Maintains chainablity
return self;
},
// _triggerShow
// ------------
// Determines what elements get shown on scroll and click
_triggerShow: function(elem, scroll) {
var self = this;
// If the current element's parent is a header element or the next element is a nested subheader element
if (elem.parent().is(headerClass) || elem.next().is(subheaderClass)) {
// Shows the next sub-header element
self.show(elem.next(subheaderClass), scroll);
}
// If the current element's parent is a subheader element
else if (elem.parent().is(subheaderClass)) {
// Shows the parent sub-header element
self.show(elem.parent(), scroll);
}
// Maintains chainability
return self;
},
// _addCSSClasses
// --------------
// Adds CSS classes to the newly generated table of contents HTML
_addCSSClasses: function() {
// If the user wants a jqueryUI theme
if (this.options.theme === "jqueryui") {
this.focusClass = "ui-state-default";
this.hoverClass = "ui-state-hover";
//Adds the default styling to the dropdown list
this.element.addClass("ui-widget").find(".toc-title").addClass("ui-widget-header").end().find("li").addClass("ui-widget-content");
}
// If the user wants a twitterBootstrap theme
else if (this.options.theme === "bootstrap") {
this.element.find(headerClass + "," + subheaderClass).addClass("nav nav-list");
this.focusClass = "active";
}
// If the user wants a twitterBootstrap theme
else if (this.options.theme === "bootstrap3") {
this.element.find(headerClass + "," + subheaderClass).addClass("list-group");
this.element.find(itemClass).addClass("list-group-item");
this.focusClass = "active";
}
// If a user does not want a prebuilt theme
else {
// Adds more neutral classes (instead of jqueryui)
this.focusClass = tocFocusClassName;
this.hoverClass = tocHoverClassName;
}
//Maintains chainability
return this;
},
// setOption
// ---------
// Sets a single Tocify option after the plugin is invoked
setOption: function() {
// Calls the jQueryUI Widget Factory setOption method
$.Widget.prototype._setOption.apply(this, arguments);
},
// setOptions
// ----------
// Sets a single or multiple Tocify options after the plugin is invoked
setOptions: function() {
// Calls the jQueryUI Widget Factory setOptions method
$.Widget.prototype._setOptions.apply(this, arguments);
},
// _scrollTo
// ---------
// Scrolls to a specific element
_scrollTo: function(elem) {
var self = this,
duration = self.options.smoothScroll || 0,
scrollTo = self.options.scrollTo,
currentDiv = $('div[data-unique="' + elem.attr("data-unique") + '"]');
if (!currentDiv.length) {
return self;
}
// Once all animations on the page are complete, this callback function will be called
$("html, body").promise().done(function() {
// Animates the html and body element scrolltops
$("html, body").animate({
// Sets the jQuery `scrollTop` to the top offset of the HTML div tag that matches the current list item's `data-unique` tag
"scrollTop": currentDiv.offset().top - ($.isFunction(scrollTo) ? scrollTo.call() : scrollTo) + "px"
}, {
// Sets the smoothScroll animation time duration to the smoothScrollSpeed option
"duration": duration
});
});
// Maintains chainability
return self;
}
});
})); //end of plugin
</script>
<script>
/**
* jQuery Plugin: Sticky Tabs
*
* @author Aidan Lister <aidan@php.net>
* adapted by Ruben Arslan to activate parent tabs too
* http://www.aidanlister.com/2014/03/persisting-the-tab-state-in-bootstrap/
*/
(function($) {
"use strict";
$.fn.rmarkdownStickyTabs = function() {
var context = this;
// Show the tab corresponding with the hash in the URL, or the first tab
var showStuffFromHash = function() {
var hash = window.location.hash;
var selector = hash ? 'a[href="' + hash + '"]' : 'li.active > a';
var $selector = $(selector, context);
if($selector.data('toggle') === "tab") {
$selector.tab('show');
// walk up the ancestors of this element, show any hidden tabs
$selector.parents('.section.tabset').each(function(i, elm) {
var link = $('a[href="#' + $(elm).attr('id') + '"]');
if(link.data('toggle') === "tab") {
link.tab("show");
}
});
}
};
// Set the correct tab when the page loads
showStuffFromHash(context);
// Set the correct tab when a user uses their back/forward button
$(window).on('hashchange', function() {
showStuffFromHash(context);
});
// Change the URL when tabs are clicked
$('a', context).on('click', function(e) {
history.pushState(null, null, this.href);
showStuffFromHash(context);
});
return this;
};
}(jQuery));
window.buildTabsets = function(tocID) {
// build a tabset from a section div with the .tabset class
function buildTabset(tabset) {
// check for fade and pills options
var fade = tabset.hasClass("tabset-fade");
var pills = tabset.hasClass("tabset-pills");
var navClass = pills ? "nav-pills" : "nav-tabs";
// determine the heading level of the tabset and tabs
var match = tabset.attr('class').match(/level(\d) /);
if (match === null)
return;
var tabsetLevel = Number(match[1]);
var tabLevel = tabsetLevel + 1;
// find all subheadings immediately below
var tabs = tabset.find("div.section.level" + tabLevel);
if (!tabs.length)
return;
// create tablist and tab-content elements
var tabList = $('<ul class="nav ' + navClass + '" role="tablist"></ul>');
$(tabs[0]).before(tabList);
var tabContent = $('<div class="tab-content"></div>');
$(tabs[0]).before(tabContent);
// build the tabset
var activeTab = 0;
tabs.each(function(i) {
// get the tab div
var tab = $(tabs[i]);
// get the id then sanitize it for use with bootstrap tabs
var id = tab.attr('id');
// see if this is marked as the active tab
if (tab.hasClass('active'))
activeTab = i;
// remove any table of contents entries associated with
// this ID (since we'll be removing the heading element)
$("div#" + tocID + " li a[href='#" + id + "']").parent().remove();
// sanitize the id for use with bootstrap tabs
id = id.replace(/[.\/?&!#<>]/g, '').replace(/\s/g, '_');
tab.attr('id', id);
// get the heading element within it, grab it's text, then remove it
var heading = tab.find('h' + tabLevel + ':first');
var headingText = heading.html();
heading.remove();
// build and append the tab list item
var a = $('<a role="tab" data-toggle="tab">' + headingText + '</a>');
a.attr('href', '#' + id);
a.attr('aria-controls', id);
var li = $('<li role="presentation"></li>');
li.append(a);
tabList.append(li);
// set it's attributes
tab.attr('role', 'tabpanel');
tab.addClass('tab-pane');
tab.addClass('tabbed-pane');
if (fade)
tab.addClass('fade');
// move it into the tab content div
tab.detach().appendTo(tabContent);
});
// set active tab
$(tabList.children('li')[activeTab]).addClass('active');
var active = $(tabContent.children('div.section')[activeTab]);
active.addClass('active');
if (fade)
active.addClass('in');
if (tabset.hasClass("tabset-sticky"))
tabset.rmarkdownStickyTabs();
}
// convert section divs with the .tabset class to tabsets
var tabsets = $("div.section.tabset");
tabsets.each(function(i) {
buildTabset($(tabsets[i]));
});
};
</script>
<style type="text/css">@layer htmltools {
.html-fill-container {
display: flex;
flex-direction: column;
min-height: 0;
min-width: 0;
}
.html-fill-container > .html-fill-item {
flex: 1 1 auto;
min-height: 0;
min-width: 0;
}
.html-fill-container > :not(.html-fill-item) {
flex: 0 0 auto;
}
}
</style>
<script>(function() {
// If window.HTMLWidgets is already defined, then use it; otherwise create a
// new object. This allows preceding code to set options that affect the
// initialization process (though none currently exist).
window.HTMLWidgets = window.HTMLWidgets || {};
// See if we're running in a viewer pane. If not, we're in a web browser.
var viewerMode = window.HTMLWidgets.viewerMode =
/\bviewer_pane=1\b/.test(window.location);
// See if we're running in Shiny mode. If not, it's a static document.
// Note that static widgets can appear in both Shiny and static modes, but
// obviously, Shiny widgets can only appear in Shiny apps/documents.
var shinyMode = window.HTMLWidgets.shinyMode =
typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings;
// We can't count on jQuery being available, so we implement our own
// version if necessary.
function querySelectorAll(scope, selector) {
if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) {
return scope.find(selector);
}
if (scope.querySelectorAll) {
return scope.querySelectorAll(selector);
}
}
function asArray(value) {
if (value === null)
return [];
if ($.isArray(value))
return value;
return [value];
}
// Implement jQuery's extend
function extend(target /*, ... */) {
if (arguments.length == 1) {
return target;
}
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
}
return target;
}
// IE8 doesn't support Array.forEach.
function forEach(values, callback, thisArg) {
if (values.forEach) {
values.forEach(callback, thisArg);
} else {
for (var i = 0; i < values.length; i++) {
callback.call(thisArg, values[i], i, values);
}
}
}
// Replaces the specified method with the return value of funcSource.
//
// Note that funcSource should not BE the new method, it should be a function
// that RETURNS the new method. funcSource receives a single argument that is
// the overridden method, it can be called from the new method. The overridden
// method can be called like a regular function, it has the target permanently
// bound to it so "this" will work correctly.
function overrideMethod(target, methodName, funcSource) {
var superFunc = target[methodName] || function() {};
var superFuncBound = function() {
return superFunc.apply(target, arguments);
};
target[methodName] = funcSource(superFuncBound);
}
// Add a method to delegator that, when invoked, calls
// delegatee.methodName. If there is no such method on
// the delegatee, but there was one on delegator before
// delegateMethod was called, then the original version
// is invoked instead.
// For example:
//
// var a = {
// method1: function() { console.log('a1'); }
// method2: function() { console.log('a2'); }
// };
// var b = {
// method1: function() { console.log('b1'); }
// };
// delegateMethod(a, b, "method1");
// delegateMethod(a, b, "method2");
// a.method1();
// a.method2();
//
// The output would be "b1", "a2".
function delegateMethod(delegator, delegatee, methodName) {
var inherited = delegator[methodName];
delegator[methodName] = function() {
var target = delegatee;
var method = delegatee[methodName];
// The method doesn't exist on the delegatee. Instead,
// call the method on the delegator, if it exists.
if (!method) {
target = delegator;
method = inherited;
}
if (method) {
return method.apply(target, arguments);
}
};
}
// Implement a vague facsimilie of jQuery's data method
function elementData(el, name, value) {
if (arguments.length == 2) {
return el["htmlwidget_data_" + name];
} else if (arguments.length == 3) {
el["htmlwidget_data_" + name] = value;
return el;
} else {
throw new Error("Wrong number of arguments for elementData: " +
arguments.length);
}
}
// http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function hasClass(el, className) {
var re = new RegExp("\\b" + escapeRegExp(className) + "\\b");
return re.test(el.className);
}
// elements - array (or array-like object) of HTML elements
// className - class name to test for
// include - if true, only return elements with given className;
// if false, only return elements *without* given className
function filterByClass(elements, className, include) {
var results = [];
for (var i = 0; i < elements.length; i++) {
if (hasClass(elements[i], className) == include)
results.push(elements[i]);
}
return results;
}
function on(obj, eventName, func) {
if (obj.addEventListener) {
obj.addEventListener(eventName, func, false);
} else if (obj.attachEvent) {
obj.attachEvent(eventName, func);
}
}
function off(obj, eventName, func) {
if (obj.removeEventListener)
obj.removeEventListener(eventName, func, false);
else if (obj.detachEvent) {
obj.detachEvent(eventName, func);
}
}
// Translate array of values to top/right/bottom/left, as usual with
// the "padding" CSS property
// https://developer.mozilla.org/en-US/docs/Web/CSS/padding
function unpackPadding(value) {
if (typeof(value) === "number")
value = [value];
if (value.length === 1) {
return {top: value[0], right: value[0], bottom: value[0], left: value[0]};
}
if (value.length === 2) {
return {top: value[0], right: value[1], bottom: value[0], left: value[1]};
}
if (value.length === 3) {
return {top: value[0], right: value[1], bottom: value[2], left: value[1]};
}
if (value.length === 4) {
return {top: value[0], right: value[1], bottom: value[2], left: value[3]};
}
}
// Convert an unpacked padding object to a CSS value
function paddingToCss(paddingObj) {
return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px";
}
// Makes a number suitable for CSS
function px(x) {
if (typeof(x) === "number")
return x + "px";
else
return x;
}
// Retrieves runtime widget sizing information for an element.
// The return value is either null, or an object with fill, padding,
// defaultWidth, defaultHeight fields.
function sizingPolicy(el) {
var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']");
if (!sizingEl)
return null;
var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}");
if (viewerMode) {
return sp.viewer;
} else {
return sp.browser;
}
}
// @param tasks Array of strings (or falsy value, in which case no-op).
// Each element must be a valid JavaScript expression that yields a
// function. Or, can be an array of objects with "code" and "data"
// properties; in this case, the "code" property should be a string
// of JS that's an expr that yields a function, and "data" should be
// an object that will be added as an additional argument when that
// function is called.
// @param target The object that will be "this" for each function
// execution.
// @param args Array of arguments to be passed to the functions. (The
// same arguments will be passed to all functions.)
function evalAndRun(tasks, target, args) {
if (tasks) {
forEach(tasks, function(task) {
var theseArgs = args;
if (typeof(task) === "object") {
theseArgs = theseArgs.concat([task.data]);
task = task.code;
}
var taskFunc = tryEval(task);
if (typeof(taskFunc) !== "function") {
throw new Error("Task must be a function! Source:\n" + task);
}
taskFunc.apply(target, theseArgs);
});
}
}
// Attempt eval() both with and without enclosing in parentheses.
// Note that enclosing coerces a function declaration into
// an expression that eval() can parse
// (otherwise, a SyntaxError is thrown)
function tryEval(code) {
var result = null;
try {
result = eval("(" + code + ")");
} catch(error) {
if (!(error instanceof SyntaxError)) {
throw error;
}
try {
result = eval(code);
} catch(e) {
if (e instanceof SyntaxError) {
throw error;
} else {
throw e;
}
}
}
return result;
}
function initSizing(el) {
var sizing = sizingPolicy(el);
if (!sizing)
return;
var cel = document.getElementById("htmlwidget_container");
if (!cel)
return;
if (typeof(sizing.padding) !== "undefined") {
document.body.style.margin = "0";
document.body.style.padding = paddingToCss(unpackPadding(sizing.padding));
}
if (sizing.fill) {
document.body.style.overflow = "hidden";
document.body.style.width = "100%";
document.body.style.height = "100%";
document.documentElement.style.width = "100%";
document.documentElement.style.height = "100%";
cel.style.position = "absolute";
var pad = unpackPadding(sizing.padding);
cel.style.top = pad.top + "px";
cel.style.right = pad.right + "px";
cel.style.bottom = pad.bottom + "px";
cel.style.left = pad.left + "px";
el.style.width = "100%";
el.style.height = "100%";
return {
getWidth: function() { return cel.getBoundingClientRect().width; },
getHeight: function() { return cel.getBoundingClientRect().height; }
};
} else {
el.style.width = px(sizing.width);
el.style.height = px(sizing.height);
return {
getWidth: function() { return cel.getBoundingClientRect().width; },
getHeight: function() { return cel.getBoundingClientRect().height; }
};
}
}
// Default implementations for methods
var defaults = {
find: function(scope) {
return querySelectorAll(scope, "." + this.name);
},
renderError: function(el, err) {
var $el = $(el);
this.clearError(el);
// Add all these error classes, as Shiny does
var errClass = "shiny-output-error";
if (err.type !== null) {
// use the classes of the error condition as CSS class names
errClass = errClass + " " + $.map(asArray(err.type), function(type) {
return errClass + "-" + type;
}).join(" ");
}
errClass = errClass + " htmlwidgets-error";
// Is el inline or block? If inline or inline-block, just display:none it
// and add an inline error.
var display = $el.css("display");
$el.data("restore-display-mode", display);
if (display === "inline" || display === "inline-block") {
$el.hide();
if (err.message !== "") {
var errorSpan = $("<span>").addClass(errClass);
errorSpan.text(err.message);
$el.after(errorSpan);
}
} else if (display === "block") {
// If block, add an error just after the el, set visibility:none on the
// el, and position the error to be on top of the el.
// Mark it with a unique ID and CSS class so we can remove it later.
$el.css("visibility", "hidden");
if (err.message !== "") {
var errorDiv = $("<div>").addClass(errClass).css("position", "absolute")
.css("top", el.offsetTop)
.css("left", el.offsetLeft)
// setting width can push out the page size, forcing otherwise
// unnecessary scrollbars to appear and making it impossible for
// the element to shrink; so use max-width instead
.css("maxWidth", el.offsetWidth)
.css("height", el.offsetHeight);
errorDiv.text(err.message);
$el.after(errorDiv);
// Really dumb way to keep the size/position of the error in sync with
// the parent element as the window is resized or whatever.
var intId = setInterval(function() {
if (!errorDiv[0].parentElement) {
clearInterval(intId);
return;
}
errorDiv
.css("top", el.offsetTop)
.css("left", el.offsetLeft)
.css("maxWidth", el.offsetWidth)
.css("height", el.offsetHeight);
}, 500);
}
}
},
clearError: function(el) {
var $el = $(el);
var display = $el.data("restore-display-mode");
$el.data("restore-display-mode", null);
if (display === "inline" || display === "inline-block") {
if (display)
$el.css("display", display);
$(el.nextSibling).filter(".htmlwidgets-error").remove();
} else if (display === "block"){
$el.css("visibility", "inherit");
$(el.nextSibling).filter(".htmlwidgets-error").remove();
}
},
sizing: {}
};
// Called by widget bindings to register a new type of widget. The definition
// object can contain the following properties:
// - name (required) - A string indicating the binding name, which will be
// used by default as the CSS classname to look for.
// - initialize (optional) - A function(el) that will be called once per
// widget element; if a value is returned, it will be passed as the third
// value to renderValue.
// - renderValue (required) - A function(el, data, initValue) that will be
// called with data. Static contexts will cause this to be called once per
// element; Shiny apps will cause this to be called multiple times per
// element, as the data changes.
window.HTMLWidgets.widget = function(definition) {
if (!definition.name) {
throw new Error("Widget must have a name");
}
if (!definition.type) {
throw new Error("Widget must have a type");
}
// Currently we only support output widgets
if (definition.type !== "output") {
throw new Error("Unrecognized widget type '" + definition.type + "'");
}
// TODO: Verify that .name is a valid CSS classname
// Support new-style instance-bound definitions. Old-style class-bound
// definitions have one widget "object" per widget per type/class of
// widget; the renderValue and resize methods on such widget objects
// take el and instance arguments, because the widget object can't
// store them. New-style instance-bound definitions have one widget
// object per widget instance; the definition that's passed in doesn't
// provide renderValue or resize methods at all, just the single method
// factory(el, width, height)
// which returns an object that has renderValue(x) and resize(w, h).
// This enables a far more natural programming style for the widget
// author, who can store per-instance state using either OO-style
// instance fields or functional-style closure variables (I guess this
// is in contrast to what can only be called C-style pseudo-OO which is
// what we required before).
if (definition.factory) {
definition = createLegacyDefinitionAdapter(definition);
}
if (!definition.renderValue) {
throw new Error("Widget must have a renderValue function");
}
// For static rendering (non-Shiny), use a simple widget registration
// scheme. We also use this scheme for Shiny apps/documents that also
// contain static widgets.
window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || [];
// Merge defaults into the definition; don't mutate the original definition.
var staticBinding = extend({}, defaults, definition);
overrideMethod(staticBinding, "find", function(superfunc) {
return function(scope) {
var results = superfunc(scope);
// Filter out Shiny outputs, we only want the static kind
return filterByClass(results, "html-widget-output", false);
};
});
window.HTMLWidgets.widgets.push(staticBinding);
if (shinyMode) {
// Shiny is running. Register the definition with an output binding.
// The definition itself will not be the output binding, instead
// we will make an output binding object that delegates to the
// definition. This is because we foolishly used the same method
// name (renderValue) for htmlwidgets definition and Shiny bindings
// but they actually have quite different semantics (the Shiny
// bindings receive data that includes lots of metadata that it
// strips off before calling htmlwidgets renderValue). We can't
// just ignore the difference because in some widgets it's helpful
// to call this.renderValue() from inside of resize(), and if
// we're not delegating, then that call will go to the Shiny
// version instead of the htmlwidgets version.
// Merge defaults with definition, without mutating either.
var bindingDef = extend({}, defaults, definition);
// This object will be our actual Shiny binding.
var shinyBinding = new Shiny.OutputBinding();
// With a few exceptions, we'll want to simply use the bindingDef's
// version of methods if they are available, otherwise fall back to
// Shiny's defaults. NOTE: If Shiny's output bindings gain additional
// methods in the future, and we want them to be overrideable by
// HTMLWidget binding definitions, then we'll need to add them to this
// list.
delegateMethod(shinyBinding, bindingDef, "getId");
delegateMethod(shinyBinding, bindingDef, "onValueChange");
delegateMethod(shinyBinding, bindingDef, "onValueError");
delegateMethod(shinyBinding, bindingDef, "renderError");
delegateMethod(shinyBinding, bindingDef, "clearError");
delegateMethod(shinyBinding, bindingDef, "showProgress");
// The find, renderValue, and resize are handled differently, because we
// want to actually decorate the behavior of the bindingDef methods.
shinyBinding.find = function(scope) {
var results = bindingDef.find(scope);
// Only return elements that are Shiny outputs, not static ones
var dynamicResults = results.filter(".html-widget-output");
// It's possible that whatever caused Shiny to think there might be
// new dynamic outputs, also caused there to be new static outputs.
// Since there might be lots of different htmlwidgets bindings, we
// schedule execution for later--no need to staticRender multiple
// times.
if (results.length !== dynamicResults.length)
scheduleStaticRender();
return dynamicResults;
};
// Wrap renderValue to handle initialization, which unfortunately isn't
// supported natively by Shiny at the time of this writing.
shinyBinding.renderValue = function(el, data) {
Shiny.renderDependencies(data.deps);
// Resolve strings marked as javascript literals to objects
if (!(data.evals instanceof Array)) data.evals = [data.evals];
for (var i = 0; data.evals && i < data.evals.length; i++) {
window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]);
}
if (!bindingDef.renderOnNullValue) {
if (data.x === null) {
el.style.visibility = "hidden";
return;
} else {
el.style.visibility = "inherit";
}
}
if (!elementData(el, "initialized")) {
initSizing(el);
elementData(el, "initialized", true);
if (bindingDef.initialize) {
var rect = el.getBoundingClientRect();
var result = bindingDef.initialize(el, rect.width, rect.height);
elementData(el, "init_result", result);
}
}
bindingDef.renderValue(el, data.x, elementData(el, "init_result"));
evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]);
};
// Only override resize if bindingDef implements it
if (bindingDef.resize) {
shinyBinding.resize = function(el, width, height) {
// Shiny can call resize before initialize/renderValue have been
// called, which doesn't make sense for widgets.
if (elementData(el, "initialized")) {
bindingDef.resize(el, width, height, elementData(el, "init_result"));
}
};
}
Shiny.outputBindings.register(shinyBinding, bindingDef.name);
}
};
var scheduleStaticRenderTimerId = null;
function scheduleStaticRender() {
if (!scheduleStaticRenderTimerId) {
scheduleStaticRenderTimerId = setTimeout(function() {
scheduleStaticRenderTimerId = null;
window.HTMLWidgets.staticRender();
}, 1);
}
}
// Render static widgets after the document finishes loading
// Statically render all elements that are of this widget's class
window.HTMLWidgets.staticRender = function() {
var bindings = window.HTMLWidgets.widgets || [];
forEach(bindings, function(binding) {
var matches = binding.find(document.documentElement);
forEach(matches, function(el) {
var sizeObj = initSizing(el, binding);
var getSize = function(el) {
if (sizeObj) {
return {w: sizeObj.getWidth(), h: sizeObj.getHeight()}
} else {
var rect = el.getBoundingClientRect();
return {w: rect.width, h: rect.height}
}
};
if (hasClass(el, "html-widget-static-bound"))
return;
el.className = el.className + " html-widget-static-bound";
var initResult;
if (binding.initialize) {
var size = getSize(el);
initResult = binding.initialize(el, size.w, size.h);
elementData(el, "init_result", initResult);
}
if (binding.resize) {
var lastSize = getSize(el);
var resizeHandler = function(e) {
var size = getSize(el);
if (size.w === 0 && size.h === 0)
return;
if (size.w === lastSize.w && size.h === lastSize.h)
return;
lastSize = size;
binding.resize(el, size.w, size.h, initResult);
};
on(window, "resize", resizeHandler);
// This is needed for cases where we're running in a Shiny
// app, but the widget itself is not a Shiny output, but
// rather a simple static widget. One example of this is
// an rmarkdown document that has runtime:shiny and widget
// that isn't in a render function. Shiny only knows to
// call resize handlers for Shiny outputs, not for static
// widgets, so we do it ourselves.
if (window.jQuery) {
window.jQuery(document).on(
"shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
resizeHandler
);
window.jQuery(document).on(
"hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
resizeHandler
);
}
// This is needed for the specific case of ioslides, which
// flips slides between display:none and display:block.
// Ideally we would not have to have ioslide-specific code
// here, but rather have ioslides raise a generic event,
// but the rmarkdown package just went to CRAN so the
// window to getting that fixed may be long.
if (window.addEventListener) {
// It's OK to limit this to window.addEventListener
// browsers because ioslides itself only supports
// such browsers.
on(document, "slideenter", resizeHandler);
on(document, "slideleave", resizeHandler);
}
}
var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']");
if (scriptData) {
var data = JSON.parse(scriptData.textContent || scriptData.text);
// Resolve strings marked as javascript literals to objects
if (!(data.evals instanceof Array)) data.evals = [data.evals];
for (var k = 0; data.evals && k < data.evals.length; k++) {
window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]);
}
binding.renderValue(el, data.x, initResult);
evalAndRun(data.jsHooks.render, initResult, [el, data.x]);
}
});
});
invokePostRenderHandlers();
}
function has_jQuery3() {
if (!window.jQuery) {
return false;
}
var $version = window.jQuery.fn.jquery;
var $major_version = parseInt($version.split(".")[0]);
return $major_version >= 3;
}
/*
/ Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
/ on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
/ really means $(setTimeout(fn)).
/ https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
/
/ Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
/ one tick later than it did before, which means staticRender() is
/ called renderValue() earlier than (advanced) widget authors might be expecting.
/ https://github.com/rstudio/shiny/issues/2630
/
/ For a concrete example, leaflet has some methods (e.g., updateBounds)
/ which reference Shiny methods registered in initShiny (e.g., setInputValue).
/ Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
/ delay execution of those methods (until Shiny methods are ready)
/ https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
/
/ Ideally widget authors wouldn't need to use this setTimeout() hack that
/ leaflet uses to call Shiny methods on a staticRender(). In the long run,
/ the logic initShiny should be broken up so that method registration happens
/ right away, but binding happens later.
*/
function maybeStaticRenderLater() {
if (shinyMode && has_jQuery3()) {
window.jQuery(window.HTMLWidgets.staticRender);
} else {
window.HTMLWidgets.staticRender();
}
}
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function() {
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
maybeStaticRenderLater();
}, false);
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
if (document.readyState === "complete") {
document.detachEvent("onreadystatechange", arguments.callee);
maybeStaticRenderLater();
}
});
}
window.HTMLWidgets.getAttachmentUrl = function(depname, key) {
// If no key, default to the first item
if (typeof(key) === "undefined")
key = 1;
var link = document.getElementById(depname + "-" + key + "-attachment");
if (!link) {
throw new Error("Attachment " + depname + "/" + key + " not found in document");
}
return link.getAttribute("href");
};
window.HTMLWidgets.dataframeToD3 = function(df) {
var names = [];
var length;
for (var name in df) {
if (df.hasOwnProperty(name))
names.push(name);
if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") {
throw new Error("All fields must be arrays");
} else if (typeof(length) !== "undefined" && length !== df[name].length) {
throw new Error("All fields must be arrays of the same length");
}
length = df[name].length;
}
var results = [];
var item;
for (var row = 0; row < length; row++) {
item = {};
for (var col = 0; col < names.length; col++) {
item[names[col]] = df[names[col]][row];
}
results.push(item);
}
return results;
};
window.HTMLWidgets.transposeArray2D = function(array) {
if (array.length === 0) return array;
var newArray = array[0].map(function(col, i) {
return array.map(function(row) {
return row[i]
})
});
return newArray;
};
// Split value at splitChar, but allow splitChar to be escaped
// using escapeChar. Any other characters escaped by escapeChar
// will be included as usual (including escapeChar itself).
function splitWithEscape(value, splitChar, escapeChar) {
var results = [];
var escapeMode = false;
var currentResult = "";
for (var pos = 0; pos < value.length; pos++) {
if (!escapeMode) {
if (value[pos] === splitChar) {
results.push(currentResult);
currentResult = "";
} else if (value[pos] === escapeChar) {
escapeMode = true;
} else {
currentResult += value[pos];
}
} else {
currentResult += value[pos];
escapeMode = false;
}
}
if (currentResult !== "") {
results.push(currentResult);
}
return results;
}
// Function authored by Yihui/JJ Allaire
window.HTMLWidgets.evaluateStringMember = function(o, member) {
var parts = splitWithEscape(member, '.', '\\');
for (var i = 0, l = parts.length; i < l; i++) {
var part = parts[i];
// part may be a character or 'numeric' member name
if (o !== null && typeof o === "object" && part in o) {
if (i == (l - 1)) { // if we are at the end of the line then evalulate
if (typeof o[part] === "string")
o[part] = tryEval(o[part]);
} else { // otherwise continue to next embedded object
o = o[part];
}
}
}
};
// Retrieve the HTMLWidget instance (i.e. the return value of an
// HTMLWidget binding's initialize() or factory() function)
// associated with an element, or null if none.
window.HTMLWidgets.getInstance = function(el) {
return elementData(el, "init_result");
};
// Finds the first element in the scope that matches the selector,
// and returns the HTMLWidget instance (i.e. the return value of
// an HTMLWidget binding's initialize() or factory() function)
// associated with that element, if any. If no element matches the
// selector, or the first matching element has no HTMLWidget
// instance associated with it, then null is returned.
//
// The scope argument is optional, and defaults to window.document.
window.HTMLWidgets.find = function(scope, selector) {
if (arguments.length == 1) {
selector = scope;
scope = document;
}
var el = scope.querySelector(selector);
if (el === null) {
return null;
} else {
return window.HTMLWidgets.getInstance(el);
}
};
// Finds all elements in the scope that match the selector, and
// returns the HTMLWidget instances (i.e. the return values of
// an HTMLWidget binding's initialize() or factory() function)
// associated with the elements, in an array. If elements that
// match the selector don't have an associated HTMLWidget
// instance, the returned array will contain nulls.
//
// The scope argument is optional, and defaults to window.document.
window.HTMLWidgets.findAll = function(scope, selector) {
if (arguments.length == 1) {
selector = scope;
scope = document;
}
var nodes = scope.querySelectorAll(selector);
var results = [];
for (var i = 0; i < nodes.length; i++) {
results.push(window.HTMLWidgets.getInstance(nodes[i]));
}
return results;
};
var postRenderHandlers = [];
function invokePostRenderHandlers() {
while (postRenderHandlers.length) {
var handler = postRenderHandlers.shift();
if (handler) {
handler();
}
}
}
// Register the given callback function to be invoked after the
// next time static widgets are rendered.
window.HTMLWidgets.addPostRenderHandler = function(callback) {
postRenderHandlers.push(callback);
};
// Takes a new-style instance-bound definition, and returns an
// old-style class-bound definition. This saves us from having
// to rewrite all the logic in this file to accomodate both
// types of definitions.
function createLegacyDefinitionAdapter(defn) {
var result = {
name: defn.name,
type: defn.type,
initialize: function(el, width, height) {
return defn.factory(el, width, height);
},
renderValue: function(el, x, instance) {
return instance.renderValue(x);
},
resize: function(el, width, height, instance) {
return instance.resize(width, height);
}
};
if (defn.find)
result.find = defn.find;
if (defn.renderError)
result.renderError = defn.renderError;
if (defn.clearError)
result.clearError = defn.clearError;
return result;
}
})();
</script>
<script>
HTMLWidgets.widget({
name: "plotly",
type: "output",
initialize: function(el, width, height) {
return {};
},
resize: function(el, width, height, instance) {
if (instance.autosize) {
var width = instance.width || width;
var height = instance.height || height;
Plotly.relayout(el.id, {width: width, height: height});
}
},
renderValue: function(el, x, instance) {
// Plotly.relayout() mutates the plot input object, so make sure to
// keep a reference to the user-supplied width/height *before*
// we call Plotly.plot();
var lay = x.layout || {};
instance.width = lay.width;
instance.height = lay.height;
instance.autosize = lay.autosize || true;
/*
/ 'inform the world' about highlighting options this is so other
/ crosstalk libraries have a chance to respond to special settings
/ such as persistent selection.
/ AFAIK, leaflet is the only library with such intergration
/ https://github.com/rstudio/leaflet/pull/346/files#diff-ad0c2d51ce5fdf8c90c7395b102f4265R154
*/
var ctConfig = crosstalk.var('plotlyCrosstalkOpts').set(x.highlight);
if (typeof(window) !== "undefined") {
// make sure plots don't get created outside the network (for on-prem)
window.PLOTLYENV = window.PLOTLYENV || {};
window.PLOTLYENV.BASE_URL = x.base_url;
// Enable persistent selection when shift key is down
// https://stackoverflow.com/questions/1828613/check-if-a-key-is-down
var persistOnShift = function(e) {
if (!e) window.event;
if (e.shiftKey) {
x.highlight.persistent = true;
x.highlight.persistentShift = true;
} else {
x.highlight.persistent = false;
x.highlight.persistentShift = false;
}
};
// Only relevant if we haven't forced persistent mode at command line
if (!x.highlight.persistent) {
window.onmousemove = persistOnShift;
}
}
var graphDiv = document.getElementById(el.id);
// TODO: move the control panel injection strategy inside here...
HTMLWidgets.addPostRenderHandler(function() {
// lower the z-index of the modebar to prevent it from highjacking hover
// (TODO: do this via CSS?)
// https://github.com/ropensci/plotly/issues/956
// https://www.w3schools.com/jsref/prop_style_zindex.asp
var modebars = document.querySelectorAll(".js-plotly-plot .plotly .modebar");
for (var i = 0; i < modebars.length; i++) {
modebars[i].style.zIndex = 1;
}
});
// inject a "control panel" holding selectize/dynamic color widget(s)
if ((x.selectize || x.highlight.dynamic) && !instance.plotly) {
var flex = document.createElement("div");
flex.class = "plotly-crosstalk-control-panel";
flex.style = "display: flex; flex-wrap: wrap";
// inject the colourpicker HTML container into the flexbox
if (x.highlight.dynamic) {
var pickerDiv = document.createElement("div");
var pickerInput = document.createElement("input");
pickerInput.id = el.id + "-colourpicker";
pickerInput.placeholder = "asdasd";
var pickerLabel = document.createElement("label");
pickerLabel.for = pickerInput.id;
pickerLabel.innerHTML = "Brush color&nbsp;&nbsp;";
pickerDiv.appendChild(pickerLabel);
pickerDiv.appendChild(pickerInput);
flex.appendChild(pickerDiv);
}
// inject selectize HTML containers (one for every crosstalk group)
if (x.selectize) {
var ids = Object.keys(x.selectize);
for (var i = 0; i < ids.length; i++) {
var container = document.createElement("div");
container.id = ids[i];
container.style = "width: 80%; height: 10%";
container.class = "form-group crosstalk-input-plotly-highlight";
var label = document.createElement("label");
label.for = ids[i];
label.innerHTML = x.selectize[ids[i]].group;
label.class = "control-label";
var selectDiv = document.createElement("div");
var select = document.createElement("select");
select.multiple = true;
selectDiv.appendChild(select);
container.appendChild(label);
container.appendChild(selectDiv);
flex.appendChild(container);
}
}
// finally, insert the flexbox inside the htmlwidget container,
// but before the plotly graph div
graphDiv.parentElement.insertBefore(flex, graphDiv);
if (x.highlight.dynamic) {
var picker = $("#" + pickerInput.id);
var colors = x.highlight.color || [];
// TODO: let users specify options?
var opts = {
value: colors[0],
showColour: "both",
palette: "limited",
allowedCols: colors.join(" "),
width: "20%",
height: "10%"
};
picker.colourpicker({changeDelay: 0});
picker.colourpicker("settings", opts);
picker.colourpicker("value", opts.value);
// inform crosstalk about a change in the current selection colour
var grps = x.highlight.ctGroups || [];
for (var i = 0; i < grps.length; i++) {
crosstalk.group(grps[i]).var('plotlySelectionColour')
.set(picker.colourpicker('value'));
}
picker.on("change", function() {
for (var i = 0; i < grps.length; i++) {
crosstalk.group(grps[i]).var('plotlySelectionColour')
.set(picker.colourpicker('value'));
}
});
}
}
// if no plot exists yet, create one with a particular configuration
if (!instance.plotly) {
var plot = Plotly.newPlot(graphDiv, x);
instance.plotly = true;
} else if (x.layout.transition) {
var plot = Plotly.react(graphDiv, x);
} else {
// this is essentially equivalent to Plotly.newPlot(), but avoids creating
// a new webgl context
// https://github.com/plotly/plotly.js/blob/2b24f9def901831e61282076cf3f835598d56f0e/src/plot_api/plot_api.js#L531-L532
// TODO: restore crosstalk selections?
Plotly.purge(graphDiv);
// TODO: why is this necessary to get crosstalk working?
graphDiv.data = undefined;
graphDiv.layout = undefined;
var plot = Plotly.newPlot(graphDiv, x);
}
// Trigger plotly.js calls defined via `plotlyProxy()`
plot.then(function() {
if (HTMLWidgets.shinyMode) {
Shiny.addCustomMessageHandler("plotly-calls", function(msg) {
var gd = document.getElementById(msg.id);
if (!gd) {
throw new Error("Couldn't find plotly graph with id: " + msg.id);
}
// This isn't an official plotly.js method, but it's the only current way to
// change just the configuration of a plot
// https://community.plot.ly/t/update-config-function/9057
if (msg.method == "reconfig") {
Plotly.react(gd, gd.data, gd.layout, msg.args);
return;
}
if (!Plotly[msg.method]) {
throw new Error("Unknown method " + msg.method);
}
var args = [gd].concat(msg.args);
Plotly[msg.method].apply(null, args);
});
}
// plotly's mapbox API doesn't currently support setting bounding boxes
// https://www.mapbox.com/mapbox-gl-js/example/fitbounds/
// so we do this manually...
// TODO: make sure this triggers on a redraw and relayout as well as on initial draw
var mapboxIDs = graphDiv._fullLayout._subplots.mapbox || [];
for (var i = 0; i < mapboxIDs.length; i++) {
var id = mapboxIDs[i];
var mapOpts = x.layout[id] || {};
var args = mapOpts._fitBounds || {};
if (!args) {
continue;
}
var mapObj = graphDiv._fullLayout[id]._subplot.map;
mapObj.fitBounds(args.bounds, args.options);
}
});
// Attach attributes (e.g., "key", "z") to plotly event data
function eventDataWithKey(eventData) {
if (eventData === undefined || !eventData.hasOwnProperty("points")) {
return null;
}
return eventData.points.map(function(pt) {
var obj = {
curveNumber: pt.curveNumber,
pointNumber: pt.pointNumber,
x: pt.x,
y: pt.y
};
// If 'z' is reported with the event data, then use it!
if (pt.hasOwnProperty("z")) {
obj.z = pt.z;
}
if (pt.hasOwnProperty("customdata")) {
obj.customdata = pt.customdata;
}
/*
TL;DR: (I think) we have to select the graph div (again) to attach keys...
Why? Remember that crosstalk will dynamically add/delete traces
(see traceManager.prototype.updateSelection() below)
For this reason, we can't simply grab keys from x.data (like we did previously)
Moreover, we can't use _fullData, since that doesn't include
unofficial attributes. It's true that click/hover events fire with
pt.data, but drag events don't...
*/
var gd = document.getElementById(el.id);
var trace = gd.data[pt.curveNumber];
if (!trace._isSimpleKey) {
var attrsToAttach = ["key"];
} else {
// simple keys fire the whole key
obj.key = trace.key;
var attrsToAttach = [];
}
for (var i = 0; i < attrsToAttach.length; i++) {
var attr = trace[attrsToAttach[i]];
if (Array.isArray(attr)) {
if (typeof pt.pointNumber === "number") {
obj[attrsToAttach[i]] = attr[pt.pointNumber];
} else if (Array.isArray(pt.pointNumber)) {
obj[attrsToAttach[i]] = attr[pt.pointNumber[0]][pt.pointNumber[1]];
} else if (Array.isArray(pt.pointNumbers)) {
obj[attrsToAttach[i]] = pt.pointNumbers.map(function(idx) { return attr[idx]; });
}
}
}
return obj;
});
}
var legendEventData = function(d) {
// if legendgroup is not relevant just return the trace
var trace = d.data[d.curveNumber];
if (!trace.legendgroup) return trace;
// if legendgroup was specified, return all traces that match the group
var legendgrps = d.data.map(function(trace){ return trace.legendgroup; });
var traces = [];
for (i = 0; i < legendgrps.length; i++) {
if (legendgrps[i] == trace.legendgroup) {
traces.push(d.data[i]);
}
}
return traces;
};
// send user input event data to shiny
if (HTMLWidgets.shinyMode && Shiny.setInputValue) {
// Some events clear other input values
// TODO: always register these?
var eventClearMap = {
plotly_deselect: ["plotly_selected", "plotly_selecting", "plotly_brushed", "plotly_brushing", "plotly_click"],
plotly_unhover: ["plotly_hover"],
plotly_doubleclick: ["plotly_click"]
};
Object.keys(eventClearMap).map(function(evt) {
graphDiv.on(evt, function() {
var inputsToClear = eventClearMap[evt];
inputsToClear.map(function(input) {
Shiny.setInputValue(input + "-" + x.source, null, {priority: "event"});
});
});
});
var eventDataFunctionMap = {
plotly_click: eventDataWithKey,
plotly_sunburstclick: eventDataWithKey,
plotly_hover: eventDataWithKey,
plotly_unhover: eventDataWithKey,
// If 'plotly_selected' has already been fired, and you click
// on the plot afterwards, this event fires `undefined`?!?
// That might be considered a plotly.js bug, but it doesn't make
// sense for this input change to occur if `d` is falsy because,
// even in the empty selection case, `d` is truthy (an object),
// and the 'plotly_deselect' event will reset this input
plotly_selected: function(d) { if (d) { return eventDataWithKey(d); } },
plotly_selecting: function(d) { if (d) { return eventDataWithKey(d); } },
plotly_brushed: function(d) {
if (d) { return d.range ? d.range : d.lassoPoints; }
},
plotly_brushing: function(d) {
if (d) { return d.range ? d.range : d.lassoPoints; }
},
plotly_legendclick: legendEventData,
plotly_legenddoubleclick: legendEventData,
plotly_clickannotation: function(d) { return d.fullAnnotation }
};
var registerShinyValue = function(event) {
var eventDataPreProcessor = eventDataFunctionMap[event] || function(d) { return d ? d : el.id };
// some events are unique to the R package
var plotlyJSevent = (event == "plotly_brushed") ? "plotly_selected" : (event == "plotly_brushing") ? "plotly_selecting" : event;
// register the event
graphDiv.on(plotlyJSevent, function(d) {
Shiny.setInputValue(
event + "-" + x.source,
JSON.stringify(eventDataPreProcessor(d)),
{priority: "event"}
);
});
}
var shinyEvents = x.shinyEvents || [];
shinyEvents.map(registerShinyValue);
}
// Given an array of {curveNumber: x, pointNumber: y} objects,
// return a hash of {
// set1: {value: [key1, key2, ...], _isSimpleKey: false},
// set2: {value: [key3, key4, ...], _isSimpleKey: false}
// }
function pointsToKeys(points) {
var keysBySet = {};
for (var i = 0; i < points.length; i++) {
var trace = graphDiv.data[points[i].curveNumber];
if (!trace.key || !trace.set) {
continue;
}
// set defaults for this keySet
// note that we don't track the nested property (yet) since we always
// emit the union -- http://cpsievert.github.io/talks/20161212b/#21
keysBySet[trace.set] = keysBySet[trace.set] || {
value: [],
_isSimpleKey: trace._isSimpleKey
};
// Use pointNumber by default, but aggregated traces should emit pointNumbers
var ptNum = points[i].pointNumber;
var hasPtNum = typeof ptNum === "number";
var ptNum = hasPtNum ? ptNum : points[i].pointNumbers;
// selecting a point of a "simple" trace means: select the
// entire key attached to this trace, which is useful for,
// say clicking on a fitted line to select corresponding observations
var key = trace._isSimpleKey ? trace.key : Array.isArray(ptNum) ? ptNum.map(function(idx) { return trace.key[idx]; }) : trace.key[ptNum];
// http://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays-in-javascript
var keyFlat = trace._isNestedKey ? [].concat.apply([], key) : key;
// TODO: better to only add new values?
keysBySet[trace.set].value = keysBySet[trace.set].value.concat(keyFlat);
}
return keysBySet;
}
x.highlight.color = x.highlight.color || [];
// make sure highlight color is an array
if (!Array.isArray(x.highlight.color)) {
x.highlight.color = [x.highlight.color];
}
var traceManager = new TraceManager(graphDiv, x.highlight);
// Gather all *unique* sets.
var allSets = [];
for (var curveIdx = 0; curveIdx < x.data.length; curveIdx++) {
var newSet = x.data[curveIdx].set;
if (newSet) {
if (allSets.indexOf(newSet) === -1) {
allSets.push(newSet);
}
}
}
// register event listeners for all sets
for (var i = 0; i < allSets.length; i++) {
var set = allSets[i];
var selection = new crosstalk.SelectionHandle(set);
var filter = new crosstalk.FilterHandle(set);
var filterChange = function(e) {
removeBrush(el);
traceManager.updateFilter(set, e.value);
};
filter.on("change", filterChange);
var selectionChange = function(e) {
// Workaround for 'plotly_selected' now firing previously selected
// points (in addition to new ones) when holding shift key. In our case,
// we just want the new keys
if (x.highlight.on === "plotly_selected" && x.highlight.persistentShift) {
// https://stackoverflow.com/questions/1187518/how-to-get-the-difference-between-two-arrays-in-javascript
Array.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;});
};
e.value = e.value.diff(e.oldValue);
}
// array of "event objects" tracking the selection history
// this is used to avoid adding redundant selections
var selectionHistory = crosstalk.var("plotlySelectionHistory").get() || [];
// Construct an event object "defining" the current event.
var event = {
receiverID: traceManager.gd.id,
plotlySelectionColour: crosstalk.group(set).var("plotlySelectionColour").get()
};
event[set] = e.value;
// TODO: is there a smarter way to check object equality?
if (selectionHistory.length > 0) {
var ev = JSON.stringify(event);
for (var i = 0; i < selectionHistory.length; i++) {
var sel = JSON.stringify(selectionHistory[i]);
if (sel == ev) {
return;
}
}
}
// accumulate history for persistent selection
if (!x.highlight.persistent) {
selectionHistory = [event];
} else {
selectionHistory.push(event);
}
crosstalk.var("plotlySelectionHistory").set(selectionHistory);
// do the actual updating of traces, frames, and the selectize widget
traceManager.updateSelection(set, e.value);
// https://github.com/selectize/selectize.js/blob/master/docs/api.md#methods_items
if (x.selectize) {
if (!x.highlight.persistent || e.value === null) {
selectize.clear(true);
}
selectize.addItems(e.value, true);
selectize.close();
}
}
selection.on("change", selectionChange);
// Set a crosstalk variable selection value, triggering an update
var turnOn = function(e) {
if (e) {
var selectedKeys = pointsToKeys(e.points);
// Keys are group names, values are array of selected keys from group.
for (var set in selectedKeys) {
if (selectedKeys.hasOwnProperty(set)) {
selection.set(selectedKeys[set].value, {sender: el});
}
}
}
};
if (x.highlight.debounce > 0) {
turnOn = debounce(turnOn, x.highlight.debounce);
}
graphDiv.on(x.highlight.on, turnOn);
graphDiv.on(x.highlight.off, function turnOff(e) {
// remove any visual clues
removeBrush(el);
// remove any selection history
crosstalk.var("plotlySelectionHistory").set(null);
// trigger the actual removal of selection traces
selection.set(null, {sender: el});
});
// register a callback for selectize so that there is bi-directional
// communication between the widget and direct manipulation events
if (x.selectize) {
var selectizeID = Object.keys(x.selectize)[i];
var options = x.selectize[selectizeID];
var first = [{value: "", label: "(All)"}];
var opts = $.extend({
options: first.concat(options.items),
searchField: "label",
valueField: "value",
labelField: "label",
maxItems: 50
},
options
);
var select = $("#" + selectizeID).find("select")[0];
var selectize = $(select).selectize(opts)[0].selectize;
// NOTE: this callback is triggered when *directly* altering
// dropdown items
selectize.on("change", function() {
var currentItems = traceManager.groupSelections[set] || [];
if (!x.highlight.persistent) {
removeBrush(el);
for (var i = 0; i < currentItems.length; i++) {
selectize.removeItem(currentItems[i], true);
}
}
var newItems = selectize.items.filter(function(idx) {
return currentItems.indexOf(idx) < 0;
});
if (newItems.length > 0) {
traceManager.updateSelection(set, newItems);
} else {
// Item has been removed...
// TODO: this logic won't work for dynamically changing palette
traceManager.updateSelection(set, null);
traceManager.updateSelection(set, selectize.items);
}
});
}
} // end of selectionChange
} // end of renderValue
}); // end of widget definition
/**
* @param graphDiv The Plotly graph div
* @param highlight An object with options for updating selection(s)
*/
function TraceManager(graphDiv, highlight) {
// The Plotly graph div
this.gd = graphDiv;
// Preserve the original data.
// TODO: try using Lib.extendFlat() as done in
// https://github.com/plotly/plotly.js/pull/1136
this.origData = JSON.parse(JSON.stringify(graphDiv.data));
// avoid doing this over and over
this.origOpacity = [];
for (var i = 0; i < this.origData.length; i++) {
this.origOpacity[i] = this.origData[i].opacity === 0 ? 0 : (this.origData[i].opacity || 1);
}
// key: group name, value: null or array of keys representing the
// most recently received selection for that group.
this.groupSelections = {};
// selection parameters (e.g., transient versus persistent selection)
this.highlight = highlight;
}
TraceManager.prototype.close = function() {
// TODO: Unhook all event handlers
};
TraceManager.prototype.updateFilter = function(group, keys) {
if (typeof(keys) === "undefined" || keys === null) {
this.gd.data = JSON.parse(JSON.stringify(this.origData));
} else {
var traces = [];
for (var i = 0; i < this.origData.length; i++) {
var trace = this.origData[i];
if (!trace.key || trace.set !== group) {
continue;
}
var matchFunc = getMatchFunc(trace);
var matches = matchFunc(trace.key, keys);
if (matches.length > 0) {
if (!trace._isSimpleKey) {
// subsetArrayAttrs doesn't mutate trace (it makes a modified clone)
trace = subsetArrayAttrs(trace, matches);
}
traces.push(trace);
}
}
this.gd.data = traces;
}
Plotly.redraw(this.gd);
// NOTE: we purposely do _not_ restore selection(s), since on filter,
// axis likely will update, changing the pixel -> data mapping, leading
// to a likely mismatch in the brush outline and highlighted marks
};
TraceManager.prototype.updateSelection = function(group, keys) {
if (keys !== null && !Array.isArray(keys)) {
throw new Error("Invalid keys argument; null or array expected");
}
// if selection has been cleared, or if this is transient
// selection, delete the "selection traces"
var nNewTraces = this.gd.data.length - this.origData.length;
if (keys === null || !this.highlight.persistent && nNewTraces > 0) {
var tracesToRemove = [];
for (var i = 0; i < this.gd.data.length; i++) {
if (this.gd.data[i]._isCrosstalkTrace) tracesToRemove.push(i);
}
Plotly.deleteTraces(this.gd, tracesToRemove);
this.groupSelections[group] = keys;
} else {
// add to the groupSelection, rather than overwriting it
// TODO: can this be removed?
this.groupSelections[group] = this.groupSelections[group] || [];
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
if (this.groupSelections[group].indexOf(k) < 0) {
this.groupSelections[group].push(k);
}
}
}
if (keys === null) {
Plotly.restyle(this.gd, {"opacity": this.origOpacity});
} else if (keys.length >= 1) {
// placeholder for new "selection traces"
var traces = [];
// this variable is set in R/highlight.R
var selectionColour = crosstalk.group(group).var("plotlySelectionColour").get() ||
this.highlight.color[0];
for (var i = 0; i < this.origData.length; i++) {
// TODO: try using Lib.extendFlat() as done in
// https://github.com/plotly/plotly.js/pull/1136
var trace = JSON.parse(JSON.stringify(this.gd.data[i]));
if (!trace.key || trace.set !== group) {
continue;
}
// Get sorted array of matching indices in trace.key
var matchFunc = getMatchFunc(trace);
var matches = matchFunc(trace.key, keys);
if (matches.length > 0) {
// If this is a "simple" key, that means select the entire trace
if (!trace._isSimpleKey) {
trace = subsetArrayAttrs(trace, matches);
}
// reach into the full trace object so we can properly reflect the
// selection attributes in every view
var d = this.gd._fullData[i];
/*
/ Recursively inherit selection attributes from various sources,
/ in order of preference:
/ (1) official plotly.js selected attribute
/ (2) highlight(selected = attrs_selected(...))
*/
// TODO: it would be neat to have a dropdown to dynamically specify these!
$.extend(true, trace, this.highlight.selected);
// if it is defined, override color with the "dynamic brush color""
if (d.marker) {
trace.marker = trace.marker || {};
trace.marker.color = selectionColour || trace.marker.color || d.marker.color;
}
if (d.line) {
trace.line = trace.line || {};
trace.line.color = selectionColour || trace.line.color || d.line.color;
}
if (d.textfont) {
trace.textfont = trace.textfont || {};
trace.textfont.color = selectionColour || trace.textfont.color || d.textfont.color;
}
if (d.fillcolor) {
// TODO: should selectionColour inherit alpha from the existing fillcolor?
trace.fillcolor = selectionColour || trace.fillcolor || d.fillcolor;
}
// attach a sensible name/legendgroup
trace.name = trace.name || keys.join("<br />");
trace.legendgroup = trace.legendgroup || keys.join("<br />");
// keep track of mapping between this new trace and the trace it targets
// (necessary for updating frames to reflect the selection traces)
trace._originalIndex = i;
trace._newIndex = this.gd._fullData.length + traces.length;
trace._isCrosstalkTrace = true;
traces.push(trace);
}
}
if (traces.length > 0) {
Plotly.addTraces(this.gd, traces).then(function(gd) {
// incrementally add selection traces to frames
// (this is heavily inspired by Plotly.Plots.modifyFrames()
// in src/plots/plots.js)
var _hash = gd._transitionData._frameHash;
var _frames = gd._transitionData._frames || [];
for (var i = 0; i < _frames.length; i++) {
// add to _frames[i].traces *if* this frame references selected trace(s)
var newIndices = [];
for (var j = 0; j < traces.length; j++) {
var tr = traces[j];
if (_frames[i].traces.indexOf(tr._originalIndex) > -1) {
newIndices.push(tr._newIndex);
_frames[i].traces.push(tr._newIndex);
}
}
// nothing to do...
if (newIndices.length === 0) {
continue;
}
var ctr = 0;
var nFrameTraces = _frames[i].data.length;
for (var j = 0; j < nFrameTraces; j++) {
var frameTrace = _frames[i].data[j];
if (!frameTrace.key || frameTrace.set !== group) {
continue;
}
var matchFunc = getMatchFunc(frameTrace);
var matches = matchFunc(frameTrace.key, keys);
if (matches.length > 0) {
if (!trace._isSimpleKey) {
frameTrace = subsetArrayAttrs(frameTrace, matches);
}
var d = gd._fullData[newIndices[ctr]];
if (d.marker) {
frameTrace.marker = d.marker;
}
if (d.line) {
frameTrace.line = d.line;
}
if (d.textfont) {
frameTrace.textfont = d.textfont;
}
ctr = ctr + 1;
_frames[i].data.push(frameTrace);
}
}
// update gd._transitionData._frameHash
_hash[_frames[i].name] = _frames[i];
}
});
// dim traces that have a set matching the set of selection sets
var tracesToDim = [],
opacities = [],
sets = Object.keys(this.groupSelections),
n = this.origData.length;
for (var i = 0; i < n; i++) {
var opacity = this.origOpacity[i] || 1;
// have we already dimmed this trace? Or is this even worth doing?
if (opacity !== this.gd._fullData[i].opacity || this.highlight.opacityDim === 1) {
continue;
}
// is this set an element of the set of selection sets?
var matches = findMatches(sets, [this.gd.data[i].set]);
if (matches.length) {
tracesToDim.push(i);
opacities.push(opacity * this.highlight.opacityDim);
}
}
if (tracesToDim.length > 0) {
Plotly.restyle(this.gd, {"opacity": opacities}, tracesToDim);
// turn off the selected/unselected API
Plotly.restyle(this.gd, {"selectedpoints": null});
}
}
}
};
/*
Note: in all of these match functions, we assume needleSet (i.e. the selected keys)
is a 1D (or flat) array. The real difference is the meaning of haystack.
findMatches() does the usual thing you'd expect for
linked brushing on a scatterplot matrix. findSimpleMatches() returns a match iff
haystack is a subset of the needleSet. findNestedMatches() returns
*/
function getMatchFunc(trace) {
return (trace._isNestedKey) ? findNestedMatches :
(trace._isSimpleKey) ? findSimpleMatches : findMatches;
}
// find matches for "flat" keys
function findMatches(haystack, needleSet) {
var matches = [];
haystack.forEach(function(obj, i) {
if (obj === null || needleSet.indexOf(obj) >= 0) {
matches.push(i);
}
});
return matches;
}
// find matches for "simple" keys
function findSimpleMatches(haystack, needleSet) {
var match = haystack.every(function(val) {
return val === null || needleSet.indexOf(val) >= 0;
});
// yes, this doesn't make much sense other than conforming
// to the output type of the other match functions
return (match) ? [0] : []
}
// find matches for a "nested" haystack (2D arrays)
function findNestedMatches(haystack, needleSet) {
var matches = [];
for (var i = 0; i < haystack.length; i++) {
var hay = haystack[i];
var match = hay.every(function(val) {
return val === null || needleSet.indexOf(val) >= 0;
});
if (match) {
matches.push(i);
}
}
return matches;
}
function isPlainObject(obj) {
return (
Object.prototype.toString.call(obj) === '[object Object]' &&
Object.getPrototypeOf(obj) === Object.prototype
);
}
function subsetArrayAttrs(obj, indices) {
var newObj = {};
Object.keys(obj).forEach(function(k) {
var val = obj[k];
if (k.charAt(0) === "_") {
newObj[k] = val;
} else if (k === "transforms" && Array.isArray(val)) {
newObj[k] = val.map(function(transform) {
return subsetArrayAttrs(transform, indices);
});
} else if (k === "colorscale" && Array.isArray(val)) {
newObj[k] = val;
} else if (isPlainObject(val)) {
newObj[k] = subsetArrayAttrs(val, indices);
} else if (Array.isArray(val)) {
newObj[k] = subsetArray(val, indices);
} else {
newObj[k] = val;
}
});
return newObj;
}
function subsetArray(arr, indices) {
var result = [];
for (var i = 0; i < indices.length; i++) {
result.push(arr[indices[i]]);
}
return result;
}
// Convenience function for removing plotly's brush
function removeBrush(el) {
var outlines = el.querySelectorAll(".select-outline");
for (var i = 0; i < outlines.length; i++) {
outlines[i].remove();
}
}
// https://davidwalsh.name/javascript-debounce-function
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
</script>
<script>(function(global){"use strict";var undefined=void 0;var MAX_ARRAY_LENGTH=1e5;function Type(v){switch(typeof v){case"undefined":return"undefined";case"boolean":return"boolean";case"number":return"number";case"string":return"string";default:return v===null?"null":"object"}}function Class(v){return Object.prototype.toString.call(v).replace(/^\[object *|\]$/g,"")}function IsCallable(o){return typeof o==="function"}function ToObject(v){if(v===null||v===undefined)throw TypeError();return Object(v)}function ToInt32(v){return v>>0}function ToUint32(v){return v>>>0}var LN2=Math.LN2,abs=Math.abs,floor=Math.floor,log=Math.log,max=Math.max,min=Math.min,pow=Math.pow,round=Math.round;(function(){var orig=Object.defineProperty;var dom_only=!function(){try{return Object.defineProperty({},"x",{})}catch(_){return false}}();if(!orig||dom_only){Object.defineProperty=function(o,prop,desc){if(orig)try{return orig(o,prop,desc)}catch(_){}if(o!==Object(o))throw TypeError("Object.defineProperty called on non-object");if(Object.prototype.__defineGetter__&&"get"in desc)Object.prototype.__defineGetter__.call(o,prop,desc.get);if(Object.prototype.__defineSetter__&&"set"in desc)Object.prototype.__defineSetter__.call(o,prop,desc.set);if("value"in desc)o[prop]=desc.value;return o}}})();function makeArrayAccessors(obj){if(obj.length>MAX_ARRAY_LENGTH)throw RangeError("Array too large for polyfill");function makeArrayAccessor(index){Object.defineProperty(obj,index,{get:function(){return obj._getter(index)},set:function(v){obj._setter(index,v)},enumerable:true,configurable:false})}var i;for(i=0;i<obj.length;i+=1){makeArrayAccessor(i)}}function as_signed(value,bits){var s=32-bits;return value<<s>>s}function as_unsigned(value,bits){var s=32-bits;return value<<s>>>s}function packI8(n){return[n&255]}function unpackI8(bytes){return as_signed(bytes[0],8)}function packU8(n){return[n&255]}function unpackU8(bytes){return as_unsigned(bytes[0],8)}function packU8Clamped(n){n=round(Number(n));return[n<0?0:n>255?255:n&255]}function packI16(n){return[n>>8&255,n&255]}function unpackI16(bytes){return as_signed(bytes[0]<<8|bytes[1],16)}function packU16(n){return[n>>8&255,n&255]}function unpackU16(bytes){return as_unsigned(bytes[0]<<8|bytes[1],16)}function packI32(n){return[n>>24&255,n>>16&255,n>>8&255,n&255]}function unpackI32(bytes){return as_signed(bytes[0]<<24|bytes[1]<<16|bytes[2]<<8|bytes[3],32)}function packU32(n){return[n>>24&255,n>>16&255,n>>8&255,n&255]}function unpackU32(bytes){return as_unsigned(bytes[0]<<24|bytes[1]<<16|bytes[2]<<8|bytes[3],32)}function packIEEE754(v,ebits,fbits){var bias=(1<<ebits-1)-1,s,e,f,ln,i,bits,str,bytes;function roundToEven(n){var w=floor(n),f=n-w;if(f<.5)return w;if(f>.5)return w+1;return w%2?w+1:w}if(v!==v){e=(1<<ebits)-1;f=pow(2,fbits-1);s=0}else if(v===Infinity||v===-Infinity){e=(1<<ebits)-1;f=0;s=v<0?1:0}else if(v===0){e=0;f=0;s=1/v===-Infinity?1:0}else{s=v<0;v=abs(v);if(v>=pow(2,1-bias)){e=min(floor(log(v)/LN2),1023);f=roundToEven(v/pow(2,e)*pow(2,fbits));if(f/pow(2,fbits)>=2){e=e+1;f=1}if(e>bias){e=(1<<ebits)-1;f=0}else{e=e+bias;f=f-pow(2,fbits)}}else{e=0;f=roundToEven(v/pow(2,1-bias-fbits))}}bits=[];for(i=fbits;i;i-=1){bits.push(f%2?1:0);f=floor(f/2)}for(i=ebits;i;i-=1){bits.push(e%2?1:0);e=floor(e/2)}bits.push(s?1:0);bits.reverse();str=bits.join("");bytes=[];while(str.length){bytes.push(parseInt(str.substring(0,8),2));str=str.substring(8)}return bytes}function unpackIEEE754(bytes,ebits,fbits){var bits=[],i,j,b,str,bias,s,e,f;for(i=bytes.length;i;i-=1){b=bytes[i-1];for(j=8;j;j-=1){bits.push(b%2?1:0);b=b>>1}}bits.reverse();str=bits.join("");bias=(1<<ebits-1)-1;s=parseInt(str.substring(0,1),2)?-1:1;e=parseInt(str.substring(1,1+ebits),2);f=parseInt(str.substring(1+ebits),2);if(e===(1<<ebits)-1){return f!==0?NaN:s*Infinity}else if(e>0){return s*pow(2,e-bias)*(1+f/pow(2,fbits))}else if(f!==0){return s*pow(2,-(bias-1))*(f/pow(2,fbits))}else{return s<0?-0:0}}function unpackF64(b){return unpackIEEE754(b,11,52)}function packF64(v){return packIEEE754(v,11,52)}function unpackF32(b){return unpackIEEE754(b,8,23)}function packF32(v){re
<style type="text/css">.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}
</style>
<script>!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e<l.length;e++)s(l[e]);return s}({1:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function r(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(e,t,n){return t&&r(e.prototype,t),n&&r(e,n),e}}();var i=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this._types={},this._seq=0}return r(e,[{key:"on",value:function(e,t){var n=this._types[e];n||(n=this._types[e]={});var r="sub"+this._seq++;return n[r]=t,r}},{key:"off",value:function(e,t){var n=this._types[e];if("function"==typeof t){for(var r in n)if(n.hasOwnProperty(r)&&n[r]===t)return delete n[r],r;return!1}if("string"==typeof t)return!(!n||!n[t])&&(delete n[t],t);throw new Error("Unexpected type for listener")}},{key:"trigger",value:function(e,t,n){var r=this._types[e];for(var i in r)r.hasOwnProperty(i)&&r[i].call(n,t)}}]),e}();n.default=i},{}],2:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.FilterHandle=void 0;var r=function(){function r(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(e,t,n){return t&&r(e.prototype,t),n&&r(e,n),e}}(),i=l(e("./events")),o=l(e("./filterset")),u=l(e("./group")),a=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(e("./util"));function l(e){return e&&e.__esModule?e:{default:e}}var s=1;n.FilterHandle=function(){function n(e,t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),this._eventRelay=new i.default,this._emitter=new a.SubscriptionTracker(this._eventRelay),this._group=null,this._filterSet=null,this._filterVar=null,this._varOnChangeSub=null,this._extraInfo=a.extend({sender:this},t),this._id="filter"+s++,this.setGroup(e)}return r(n,[{key:"setGroup",value:function(e){var t,n,r=this;if(this._group!==e&&((this._group||e)&&(this._filterVar&&(this._filterVar.off("change",this._varOnChangeSub),this.clear(),this._varOnChangeSub=null,this._filterVar=null,this._filterSet=null),this._group=e))){e=(0,u.default)(e),this._filterSet=(t=e.var("filterset"),(n=t.get())||(n=new o.default,t.set(n)),n),this._filterVar=(0,u.default)(e).var("filter");var i=this._filterVar.on("change",function(e){r._eventRelay.trigger("change",e,r)});this._varOnChangeSub=i}}},{key:"_mergeExtraInfo",value:function(e){return a.extend({},this._extraInfo?this._extraInfo:null,e||null)}},{key:"close",value:function(){this._emitter.removeAllListeners(),this.clear(),this.setGroup(null)}},{key:"clear",value:function(e){this._filterSet&&(this._filterSet.clear(this._id),this._onChange(e))}},{key:"set",value:function(e,t){this._filterSet&&(this._filterSet.update(this._id,e),this._onChange(t))}},{key:"on",value:function(e,t){return this._emitter.on(e,t)}},{key:"off",value:function(e,t){return this._emitter.off(e,t)}},{key:"_onChange",value:function(e){this._filterSet&&this._filterVar.set(this._filterSet.value,this._mergeExtraInfo(e))}},{key:"filteredKeys",get:function(){return this._filterSet?this._filterSet.value:null}}]),n}()},{"./events":1,"./filterset":3,"./group":4,"./util":11}],3:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function r(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.k
//# sourceMappingURL=crosstalk.min.js.map</script>
<style type="text/css">
slide:not(.current) .plotly.html-widget{
display: none;
}
</style>
<script>/**
* plotly.js v2.11.1
* Copyright 2012-2022, Plotly, Inc.
* All rights reserved.
* Licensed under the MIT license
*/
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Plotly=t()}}((function(){return function t(e,r,n){function i(o,s){if(!r[o]){if(!e[o]){var l="function"==typeof require&&require;if(!s&&l)return l(o,!0);if(a)return a(o,!0);var c=new Error("Cannot find module '"+o+"'");throw c.code="MODULE_NOT_FOUND",c}var u=r[o]={exports:{}};e[o][0].call(u.exports,(function(t){return i(e[o][1][t]||t)}),u,u.exports,t,e,r,n)}return r[o].exports}for(var a="function"==typeof require&&require,o=0;o<n.length;o++)i(n[o]);return i}({1:[function(t,e,r){"use strict";var n=t("../src/lib"),i={"X,X div":'direction:ltr;font-family:"Open Sans",verdana,arial,sans-serif;margin:0;padding:0;',"X input,X button":'font-family:"Open Sans",verdana,arial,sans-serif;',"X input:focus,X button:focus":"outline:none;","X a":"text-decoration:none;","X a:hover":"text-decoration:none;","X .crisp":"shape-rendering:crispEdges;","X .user-select-none":"-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;","X svg":"overflow:hidden;","X svg a":"fill:#447adb;","X svg a:hover":"fill:#3c6dc5;","X .main-svg":"position:absolute;top:0;left:0;pointer-events:none;","X .main-svg .draglayer":"pointer-events:all;","X .cursor-default":"cursor:default;","X .cursor-pointer":"cursor:pointer;","X .cursor-crosshair":"cursor:crosshair;","X .cursor-move":"cursor:move;","X .cursor-col-resize":"cursor:col-resize;","X .cursor-row-resize":"cursor:row-resize;","X .cursor-ns-resize":"cursor:ns-resize;","X .cursor-ew-resize":"cursor:ew-resize;","X .cursor-sw-resize":"cursor:sw-resize;","X .cursor-s-resize":"cursor:s-resize;","X .cursor-se-resize":"cursor:se-resize;","X .cursor-w-resize":"cursor:w-resize;","X .cursor-e-resize":"cursor:e-resize;","X .cursor-nw-resize":"cursor:nw-resize;","X .cursor-n-resize":"cursor:n-resize;","X .cursor-ne-resize":"cursor:ne-resize;","X .cursor-grab":"cursor:-webkit-grab;cursor:grab;","X .modebar":"position:absolute;top:2px;right:2px;","X .ease-bg":"-webkit-transition:background-color .3s ease 0s;-moz-transition:background-color .3s ease 0s;-ms-transition:background-color .3s ease 0s;-o-transition:background-color .3s ease 0s;transition:background-color .3s ease 0s;","X .modebar--hover>:not(.watermark)":"opacity:0;-webkit-transition:opacity .3s ease 0s;-moz-transition:opacity .3s ease 0s;-ms-transition:opacity .3s ease 0s;-o-transition:opacity .3s ease 0s;transition:opacity .3s ease 0s;","X:hover .modebar--hover .modebar-group":"opacity:1;","X .modebar-group":"float:left;display:inline-block;box-sizing:border-box;padding-left:8px;position:relative;vertical-align:middle;white-space:nowrap;","X .modebar-btn":"position:relative;font-size:16px;padding:3px 4px;height:22px;cursor:pointer;line-height:normal;box-sizing:border-box;","X .modebar-btn svg":"position:relative;top:2px;","X .modebar.vertical":"display:flex;flex-direction:column;flex-wrap:wrap;align-content:flex-end;max-height:100%;","X .modebar.vertical svg":"top:-1px;","X .modebar.vertical .modebar-group":"display:block;float:none;padding-left:0px;padding-bottom:8px;","X .modebar.vertical .modebar-group .modebar-btn":"display:block;text-align:center;","X [data-title]:before,X [data-title]:after":"position:absolute;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);-ms-transform:translate3d(0, 0, 0);-o-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);display:none;opacity:0;z-index:1001;pointer-events:none;top:110%;right:50%;","X [data-title]:hover:before,X [data-title]:hover:after":"display:block;opacity:1;","X [data-title]:before":'content:"";position:absolute;background:transparent;border:6px solid transparent;z-index:1002;margin-top:-12px;border-bottom-color:#69738a;margin-right:-6px;',"X [data-title]:after":"content:attr(data-title);background:#69738a;color:#fff;padding:8px 10px;font-size:12px;line-height:12px;white-spac
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/function i(t,e){if(t===e)return 0;for(var r=t.length,n=e.length,i=0,a=Math.min(r,n);i<a;++i)if(t[i]!==e[i]){r=t[i],n=e[i];break}return r<n?-1:n<r?1:0}function a(t){return r.Buffer&&"function"==typeof r.Buffer.isBuffer?r.Buffer.isBuffer(t):!(null==t||!t._isBuffer)}var o=t("util/"),s=Object.prototype.hasOwnProperty,l=Array.prototype.slice,c="foo"===function(){}.name;function u(t){return Object.prototype.toString.call(t)}function f(t){return!a(t)&&("function"==typeof r.ArrayBuffer&&("function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(t):!!t&&(t instanceof DataView||!!(t.buffer&&t.buffer instanceof ArrayBuffer))))}var h=e.exports=y,p=/\s*function\s+([^\(\s]*)\s*/;function d(t){if(o.isFunction(t)){if(c)return t.name;var e=t.toString().match(p);return e&&e[1]}}function m(t,e){return"string"==typeof t?t.length<e?t:t.slice(0,e):t}function g(t){if(c||!o.isFunction(t))return o.inspect(t);var e=d(t);return"[Function"+(e?": "+e:"")+"]"}function v(t,e,r,n,i){throw new h.AssertionError({message:r,actual:t,expected:e,operator:n,stackStartFunction:i})}function y(t,e){t||v(t,!0,e,"==",h.ok)}function x(t,e,r,n){if(t===e)return!0;if(a(t)&&a(e))return 0===i(t,e);if(o.isDate(t)&&o.isDate(e))return t.getTime()===e.getTime();if(o.isRegExp(t)&&o.isRegExp(e))return t.source===e.source&&t.global===e.global&&t.multiline===e.multiline&&t.lastIndex===e.lastIndex&&t.ignoreCase===e.ignoreCase;if(null!==t&&"object"==typeof t||null!==e&&"object"==typeof e){if(f(t)&&f(e)&&u(t)===u(e)&&!(t instanceof Float32Array||t instanceof Float64Array))return 0===i(new Uint8Array(t.buffer),new Uint8Array(e.buffer));if(a(t)!==a(e))return!1;var s=(n=n||{actual:[],expected:[]}).actual.indexOf(t);return-1!==s&&s===n.expected.indexOf(e)||(n.actual.push(t),n.expected.push(e),function(t,e,r,n){if(null==t||null==e)return!1;if(o.isPrimitive(t)||o.isPrimitive(e))return t===e;if(r&&Object.getPrototypeOf(t)!==Object.getPrototypeOf(e))return!1;var i=b(t),a=b(e);if(i&&!a||!i&&a)return!1;if(i)return t=l.call(t),e=l.call(e),x(t,e,r);var s,c,u=T(t),f=T(e);if(u.length!==f.length)return!1;for(u.sort(),f.sort(),c=u.length-1;c>=0;c--)if(u[c]!==f[c])return!1;for(c=u.length-1;c>=0;c--)if(s=u[c],!x(t[s],e[s],r,n))return!1;return!0}(t,e,r,n))}return r?t===e:t==e}function b(t){return"[object Arguments]"==Object.prototype.toString.call(t)}function _(t,e){if(!t||!e)return!1;if("[object RegExp]"==Object.prototype.toString.call(e))return e.test(t);try{if(t instanceof e)return!0}catch(t){}return!Error.isPrototypeOf(e)&&!0===e.call({},t)}function w(t,e,r,n){var i;if("function"!=typeof e)throw new TypeError('"block" argument must be a function');"string"==typeof r&&(n=r,r=null),i=function(t){var e;try{t()}catch(t){e=t}return e}(e),n=(r&&r.name?" ("+r.name+").":".")+(n?" "+n:"."),t&&!i&&v(i,r,"Missing expected exception"+n);var a="string"==typeof n,s=!t&&i&&!r;if((!t&&o.isError(i)&&a&&_(i,r)||s)&&v(i,r,"Got unwanted exception"+n),t&&i&&r&&!_(i,r)||!t&&i)throw i}h.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=function(t){return m(g(t.actual),128)+" "+t.operator+" "+m(g(t.expected),128)}(this),this.generatedMessage=!0);var e=t.stackStartFunction||v;if(Error.captureStackTrace)Error.captureStackTrace(this,e);else{var r=new Error;if(r.stack){var n=r.stack,i=d(e),a=n.indexOf("\n"+i);if(a>=0){var o=n.indexOf("\n",a+1);n=n.substring(o+1)}this.stack=n}}},o.inherits(h.AssertionError,Error),h.fail=v,h.ok=y,h.equal=function(t,e,r){t!=e&&v(t,e,r,"==",h.equal)},h.notEqual=function(t,e,r){t==e&&v(t,e,r,"!=",h.notEqual)},h.deepEqual=function(t,e,r){x(t,e,!1)||v(t,e,r,"deepEqual",h.deepEqual)},h.deepStrictEqual=function(t,e,r){x(t,e,!0)||v(t,e,r,"deepStrictEqual",h.deepStrictEqual)},h.notDeepEqual=function(t,e,r){x(t,e,!1)&&v(t,e,r,"notDeepEqual",h.notDeepEqual)},h.notDeepStrictEqual=function t(e,r,n){x(e,r,!0)&&v(e,r,n,"notDeepStrictEqual",t)},h.strictEqual=function(t,e,r){t!==e&&v(t,e,r,"===",h.strictEqual)},h.notStrictEqual=function(t,e,r){t===e&&v(t,e,r,
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
"use strict";var e=t("base64-js"),n=t("ieee754");r.Buffer=a,r.SlowBuffer=function(t){+t!=t&&(t=0);return a.alloc(+t)},r.INSPECT_MAX_BYTES=50;function i(t){if(t>2147483647)throw new RangeError('The value "'+t+'" is invalid for option "size"');var e=new Uint8Array(t);return e.__proto__=a.prototype,e}function a(t,e,r){if("number"==typeof t){if("string"==typeof e)throw new TypeError('The "string" argument must be of type string. Received type number');return l(t)}return o(t,e,r)}function o(t,e,r){if("string"==typeof t)return function(t,e){"string"==typeof e&&""!==e||(e="utf8");if(!a.isEncoding(e))throw new TypeError("Unknown encoding: "+e);var r=0|f(t,e),n=i(r),o=n.write(t,e);o!==r&&(n=n.slice(0,o));return n}(t,e);if(ArrayBuffer.isView(t))return c(t);if(null==t)throw TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t);if(B(t,ArrayBuffer)||t&&B(t.buffer,ArrayBuffer))return function(t,e,r){if(e<0||t.byteLength<e)throw new RangeError('"offset" is outside of buffer bounds');if(t.byteLength<e+(r||0))throw new RangeError('"length" is outside of buffer bounds');var n;n=void 0===e&&void 0===r?new Uint8Array(t):void 0===r?new Uint8Array(t,e):new Uint8Array(t,e,r);return n.__proto__=a.prototype,n}(t,e,r);if("number"==typeof t)throw new TypeError('The "value" argument must not be of type number. Received type number');var n=t.valueOf&&t.valueOf();if(null!=n&&n!==t)return a.from(n,e,r);var o=function(t){if(a.isBuffer(t)){var e=0|u(t.length),r=i(e);return 0===r.length||t.copy(r,0,0,e),r}if(void 0!==t.length)return"number"!=typeof t.length||N(t.length)?i(0):c(t);if("Buffer"===t.type&&Array.isArray(t.data))return c(t.data)}(t);if(o)return o;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof t[Symbol.toPrimitive])return a.from(t[Symbol.toPrimitive]("string"),e,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t)}function s(t){if("number"!=typeof t)throw new TypeError('"size" argument must be of type number');if(t<0)throw new RangeError('The value "'+t+'" is invalid for option "size"')}function l(t){return s(t),i(t<0?0:0|u(t))}function c(t){for(var e=t.length<0?0:0|u(t.length),r=i(e),n=0;n<e;n+=1)r[n]=255&t[n];return r}function u(t){if(t>=2147483647)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+2147483647..toString(16)+" bytes");return 0|t}function f(t,e){if(a.isBuffer(t))return t.length;if(ArrayBuffer.isView(t)||B(t,ArrayBuffer))return t.byteLength;if("string"!=typeof t)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof t);var r=t.length,n=arguments.length>2&&!0===arguments[2];if(!n&&0===r)return 0;for(var i=!1;;)switch(e){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return D(t).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return R(t).length;default:if(i)return n?-1:D(t).length;e=(""+e).toLowerCase(),i=!0}}function h(t,e,r){var n=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(e>>>=0))return"";for(t||(t="utf8");;)switch(t){case"hex":return M(this,e,r);case"utf8":case"utf-8":return T(this,e,r);case"ascii":return k(this,e,r);case"latin1":case"binary":return A(this,e,r);case"base64":return w(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}function p(t,e,r){var n=t[e];t[e]=t[r],t[r]=n}function d(t,e,r,n,i){if(0===t.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),N(r=+r)&&(r=i?0:t.length-1),r<0&&(r=t.length+r),r>=t.length){if(i)return-1;r=t.length-1}else if(r<0){if(!i)return-1;r=0}if("string"==typeof e&&(e=a.from(e,n)),a.isBuffer(e))return 0===e.length?-1:m(t,e,r,n,i);if("number"==typeof e)return e&=255,"functio
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
r.read=function(t,e,r,n,i){var a,o,s=8*i-n-1,l=(1<<s)-1,c=l>>1,u=-7,f=r?i-1:0,h=r?-1:1,p=t[e+f];for(f+=h,a=p&(1<<-u)-1,p>>=-u,u+=s;u>0;a=256*a+t[e+f],f+=h,u-=8);for(o=a&(1<<-u)-1,a>>=-u,u+=n;u>0;o=256*o+t[e+f],f+=h,u-=8);if(0===a)a=1-c;else{if(a===l)return o?NaN:1/0*(p?-1:1);o+=Math.pow(2,n),a-=c}return(p?-1:1)*o*Math.pow(2,a-n)},r.write=function(t,e,r,n,i,a){var o,s,l,c=8*a-i-1,u=(1<<c)-1,f=u>>1,h=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,p=n?0:a-1,d=n?1:-1,m=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(s=isNaN(e)?1:0,o=u):(o=Math.floor(Math.log(e)/Math.LN2),e*(l=Math.pow(2,-o))<1&&(o--,l*=2),(e+=o+f>=1?h/l:h*Math.pow(2,1-f))*l>=2&&(o++,l/=2),o+f>=u?(s=0,o=u):o+f>=1?(s=(e*l-1)*Math.pow(2,i),o+=f):(s=e*Math.pow(2,f-1)*Math.pow(2,i),o=0));i>=8;t[r+p]=255&s,p+=d,s/=256,i-=8);for(o=o<<i|s,c+=i;c>0;t[r+p]=255&o,p+=d,o/=256,c-=8);t[r+p-d]|=128*m}},{}],226:[function(t,e,r){"function"==typeof Object.create?e.exports=function(t,e){e&&(t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(t,e){if(e){t.super_=e;var r=function(){};r.prototype=e.prototype,t.prototype=new r,t.prototype.constructor=t}}},{}],227:[function(t,e,r){e.exports=!0},{}],228:[function(t,e,r){"use strict";e.exports="undefined"!=typeof navigator&&(/MSIE/.test(navigator.userAgent)||/Trident\//.test(navigator.appVersion))},{}],229:[function(t,e,r){"use strict";e.exports=a,e.exports.isMobile=a,e.exports.default=a;var n=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i,i=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino|android|ipad|playbook|silk/i;function a(t){t||(t={});var e=t.ua;if(e||"undefined"==typeof navigator||(e=navigator.userAgent),e&&e.headers&&"string"==typeof e.headers["user-agent"]&&(e=e.headers["user-agent"]),"string"!=typeof e)return!1;var r=t.tablet?i.test(e):n.test(e);return!r&&t.tablet&&t.featureDetect&&navigator&&navigator.maxTouchPoints>1&&-1!==e.indexOf("Macintosh")&&-1!==e.indexOf("Safari")&&(r=!0),r}},{}],230:[function(t,e,r){"use strict";e.exports=function(t){var e=typeof t;return null!==t&&("object"===e||"function"===e)}},{}],231:[function(t,e,r){"use strict";var n=Object.prototype.toString;e.exports=function(t){var e;return"[object Object]"===n.call(t)&&(null===(e=Object.getPrototypeOf(t))||e===Object.getPrototypeOf({}))}},{}],232:[function(t,e,r){"use strict";e.exports=function(t){for(var e,r=t.length,n=0;n<r;n++)if(((e=t.charCodeAt(n))<9||e>13)&&32!==e&&133!==e&&160!==e&&5760!==e&&6158!==e&&(e<8192||e>8205)&&8232!==e&&8233!==e&&8239!==e&&8287!==e&&8288!==e&&12288!==e&&65279!==e)return!1;return!0}},{}],233:[function(t,e,r){"use strict";e.exports=function(t){return"string"==typeof t&&(t=t.trim(),!!(/^[mzlhvcsqta]\s*[-+.0-9][^mlhvzcsqta]+/i.test(t)&&/[\dz]$/i.test(t)&&t.length>4))}},{}],234:[function(t,e,r){!function(t,n){"object"==typeof r&&void 0!==e?e.exports=n():(t=t||self).mapboxgl=n()}(this,(function(){"use strict";var t,e,r;function n(n,i){if(t)if(e){var a="var sharedChunk = {}; ("+t+")(sharedChunk); ("+e+")(sharedChunk);",o={};t(o),(r=i(o)).workerUrl=window.URL.createObjectURL(new Blob([a],{type:"text/javascript"}))}else e=i;else t=i}return n(0,(function(t){function e(t,e){return t(e={exports:{}},e.exports),e.exports}var r=n;function n(t,e,r,n){this.cx=3*t,this.bx=3*(r-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(n-e)-this.cy,this.ay=1-this.cy-this.by,this.p1x=t,this.p1y=n,this.p2x=r,this.p2y=n}n.prototype.sampleCurveX=function(t){return((this.ax*t+this.bx)*t+this.cx)*t},n.prototype.sampleC
/*! Native Promise Only
v0.8.1 (c) Kyle Simpson
MIT License: http://getify.mit-license.org
*/
!function(t,r,n){r[t]=r[t]||n(),void 0!==e&&e.exports&&(e.exports=r[t])}("Promise",void 0!==t?t:this,(function(){"use strict";var t,e,n,i=Object.prototype.toString,a=void 0!==r?function(t){return r(t)}:setTimeout;try{Object.defineProperty({},"x",{}),t=function(t,e,r,n){return Object.defineProperty(t,e,{value:r,writable:!0,configurable:!1!==n})}}catch(e){t=function(t,e,r){return t[e]=r,t}}function o(t,r){n.add(t,r),e||(e=a(n.drain))}function s(t){var e,r=typeof t;return null==t||"object"!=r&&"function"!=r||(e=t.then),"function"==typeof e&&e}function l(){for(var t=0;t<this.chain.length;t++)c(this,1===this.state?this.chain[t].success:this.chain[t].failure,this.chain[t]);this.chain.length=0}function c(t,e,r){var n,i;try{!1===e?r.reject(t.msg):(n=!0===e?t.msg:e.call(void 0,t.msg))===r.promise?r.reject(TypeError("Promise-chain cycle")):(i=s(n))?i.call(n,r.resolve,r.reject):r.resolve(n)}catch(t){r.reject(t)}}function u(t){var e,r=this;if(!r.triggered){r.triggered=!0,r.def&&(r=r.def);try{(e=s(t))?o((function(){var n=new p(r);try{e.call(t,(function(){u.apply(n,arguments)}),(function(){f.apply(n,arguments)}))}catch(t){f.call(n,t)}})):(r.msg=t,r.state=1,r.chain.length>0&&o(l,r))}catch(t){f.call(new p(r),t)}}}function f(t){var e=this;e.triggered||(e.triggered=!0,e.def&&(e=e.def),e.msg=t,e.state=2,e.chain.length>0&&o(l,e))}function h(t,e,r,n){for(var i=0;i<e.length;i++)!function(i){t.resolve(e[i]).then((function(t){r(i,t)}),n)}(i)}function p(t){this.def=t,this.triggered=!1}function d(t){this.promise=t,this.state=0,this.triggered=!1,this.chain=[],this.msg=void 0}function m(t){if("function"!=typeof t)throw TypeError("Not a function");if(0!==this.__NPO__)throw TypeError("Not a promise");this.__NPO__=1;var e=new d(this);this.then=function(t,r){var n={success:"function"!=typeof t||t,failure:"function"==typeof r&&r};return n.promise=new this.constructor((function(t,e){if("function"!=typeof t||"function"!=typeof e)throw TypeError("Not a function");n.resolve=t,n.reject=e})),e.chain.push(n),0!==e.state&&o(l,e),n.promise},this.catch=function(t){return this.then(void 0,t)};try{t.call(void 0,(function(t){u.call(e,t)}),(function(t){f.call(e,t)}))}catch(t){f.call(e,t)}}n=function(){var t,r,n;function i(t,e){this.fn=t,this.self=e,this.next=void 0}return{add:function(e,a){n=new i(e,a),r?r.next=n:t=n,r=n,n=void 0},drain:function(){var n=t;for(t=r=e=void 0;n;)n.fn.call(n.self),n=n.next}}}();var g=t({},"constructor",m,!1);return m.prototype=g,t(g,"__NPO__",0,!1),t(m,"resolve",(function(t){return t&&"object"==typeof t&&1===t.__NPO__?t:new this((function(e,r){if("function"!=typeof e||"function"!=typeof r)throw TypeError("Not a function");e(t)}))})),t(m,"reject",(function(t){return new this((function(e,r){if("function"!=typeof e||"function"!=typeof r)throw TypeError("Not a function");r(t)}))})),t(m,"all",(function(t){var e=this;return"[object Array]"!=i.call(t)?e.reject(TypeError("Not an array")):0===t.length?e.resolve([]):new e((function(r,n){if("function"!=typeof r||"function"!=typeof n)throw TypeError("Not a function");var i=t.length,a=Array(i),o=0;h(e,t,(function(t,e){a[t]=e,++o===i&&r(a)}),n)}))})),t(m,"race",(function(t){var e=this;return"[object Array]"!=i.call(t)?e.reject(TypeError("Not an array")):new e((function(r,n){if("function"!=typeof r||"function"!=typeof n)throw TypeError("Not a function");h(e,t,(function(t,e){r(e)}),n)}))})),m}))}).call(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},t("timers").setImmediate)},{timers:306}],241:[function(t,e,r){var n=Math.PI,i=c(120);function a(t,e,r,n){return["C",t,e,r,n,r,n]}function o(t,e,r,n,i,a){return["C",t/3+2/3*r,e/3+2/3*n,i/3+2/3*r,a/3+2/3*n,i,a]}function s(t,e,r,a,o,c,u,f,h,p){if(p)T=p[0],k=p[1],_=p[2],w=p[3];else{var d=l(t,e,-o);t=d.x,e=d.y;var m=(t-(f=(d=l(f,h,-o)).x))/2,g=(e-(h=d.y))/2,v=m*m/(r*r)+g*g/(a*a);v>1&&(r*=v=Math.sqrt(v),a*=v);var y=r*r,x=a*a,b=(c==u?-1:1)*Math.sqrt(Math.abs((y*x-y*g*g-x*m*m)/(y*g*g+x*m*m)));b==1/0&&(b=1);var _=b*r*g/a+(t+f)/2,w=b*-a*m/r+(e+h)/2,T=Math.asin(((e-w)/a).toFixed(9)),k=Math.asin(((h-
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
"use strict";var n=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;function o(t){if(null==t)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}e.exports=function(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de","5"===Object.getOwnPropertyNames(t)[0])return!1;for(var e={},r=0;r<10;r++)e["_"+String.fromCharCode(r)]=r;if("0123456789"!==Object.getOwnPropertyNames(e).map((function(t){return e[t]})).join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach((function(t){n[t]=t})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(t){return!1}}()?Object.assign:function(t,e){for(var r,s,l=o(t),c=1;c<arguments.length;c++){for(var u in r=Object(arguments[c]))i.call(r,u)&&(l[u]=r[u]);if(n){s=n(r);for(var f=0;f<s.length;f++)a.call(r,s[f])&&(l[s[f]]=r[s[f]])}}return l}},{}],243:[function(t,e,r){"use strict";function n(t,e){if("string"!=typeof t)return[t];var r=[t];"string"==typeof e||Array.isArray(e)?e={brackets:e}:e||(e={});var n=e.brackets?Array.isArray(e.brackets)?e.brackets:[e.brackets]:["{}","[]","()"],i=e.escape||"___",a=!!e.flat;n.forEach((function(t){var e=new RegExp(["\\",t[0],"[^\\",t[0],"\\",t[1],"]*\\",t[1]].join("")),n=[];function a(e,a,o){var s=r.push(e.slice(t[0].length,-t[1].length))-1;return n.push(s),i+s+i}r.forEach((function(t,n){for(var i,o=0;t!=i;)if(i=t,t=t.replace(e,a),o++>1e4)throw Error("References have circular dependency. Please, check them.");r[n]=t})),n=n.reverse(),r=r.map((function(e){return n.forEach((function(r){e=e.replace(new RegExp("(\\"+i+r+"\\"+i+")","g"),t[0]+"$1"+t[1])})),e}))}));var o=new RegExp("\\"+i+"([0-9]+)\\"+i);return a?r:function t(e,r,n){for(var i,a=[],s=0;i=o.exec(e);){if(s++>1e4)throw Error("Circular references in parenthesis");a.push(e.slice(0,i.index)),a.push(t(r[i[1]],r)),e=e.slice(i.index+i[0].length)}return a.push(e),a}(r[0],r)}function i(t,e){if(e&&e.flat){var r,n=e&&e.escape||"___",i=t[0];if(!i)return"";for(var a=new RegExp("\\"+n+"([0-9]+)\\"+n),o=0;i!=r;){if(o++>1e4)throw Error("Circular references in "+t);r=i,i=i.replace(a,s)}return i}return t.reduce((function t(e,r){return Array.isArray(r)&&(r=r.reduce(t,"")),e+r}),"");function s(e,r){if(null==t[r])throw Error("Reference "+r+"is undefined");return t[r]}}function a(t,e){return Array.isArray(t)?i(t,e):n(t,e)}a.parse=n,a.stringify=i,e.exports=a},{}],244:[function(t,e,r){"use strict";var n=t("pick-by-alias");e.exports=function(t){var e;arguments.length>1&&(t=arguments);"string"==typeof t?t=t.split(/\s/).map(parseFloat):"number"==typeof t&&(t=[t]);t.length&&"number"==typeof t[0]?e=1===t.length?{width:t[0],height:t[0],x:0,y:0}:2===t.length?{width:t[0],height:t[1],x:0,y:0}:{x:t[0],y:t[1],width:t[2]-t[0]||0,height:t[3]-t[1]||0}:t&&(t=n(t,{left:"x l left Left",top:"y t top Top",width:"w width W Width",height:"h height W Width",bottom:"b bottom Bottom",right:"r right Right"}),e={x:t.left||0,y:t.top||0},null==t.width?t.right?e.width=t.right-e.x:e.width=0:e.width=t.width,null==t.height?t.bottom?e.height=t.bottom-e.y:e.height=0:e.height=t.height);return e}},{"pick-by-alias":248}],245:[function(t,e,r){e.exports=function(t){var e=[];return t.replace(i,(function(t,r,i){var o=r.toLowerCase();for(i=function(t){var e=t.match(a);return e?e.map(Number):[]}(i),"m"==o&&i.length>2&&(e.push([r].concat(i.splice(0,2))),o="l",r="m"==r?"l":"L");;){if(i.length==n[o])return i.unshift(r),e.push(i);if(i.length<n[o])throw new Error("malformed path data");e.push([r].concat(i.splice(0,n[o])))}})),e};var n={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},i=/([astvzqmhlc])([^astvzqmhlc]*)/gi;var a=/-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi},{}],246:[function(t,e,r){e.exports=function(t,e){e||(e=[0,""]),t=String(t);var r=parseFloat(t,10);return e[0]=r,e[1]=t.match(/[\d.\-\+]*\s*(.*)/)[1]||"",e}},{}],247:[function(t,e,r){(function(t){(function(){(function(){var r,n,i,a,o,s;"undefined"!=typeof performance&&null!==performance&&performance.now?e.exports=function(){return performance.now()}:null!=t&&t.hrtime?(e.exports=functi
/*
* @copyright 2016 Sean Connelly (@voidqk), http://syntheti.cc
* @license MIT
* @preserve Project Home: https://github.com/voidqk/polybooljs
*/
var n,i=t("./lib/build-log"),a=t("./lib/epsilon"),o=t("./lib/intersecter"),s=t("./lib/segment-chainer"),l=t("./lib/segment-selector"),c=t("./lib/geojson"),u=!1,f=a();function h(t,e,r){var i=n.segments(t),a=n.segments(e),o=r(n.combine(i,a));return n.polygon(o)}n={buildLog:function(t){return!0===t?u=i():!1===t&&(u=!1),!1!==u&&u.list},epsilon:function(t){return f.epsilon(t)},segments:function(t){var e=o(!0,f,u);return t.regions.forEach(e.addRegion),{segments:e.calculate(t.inverted),inverted:t.inverted}},combine:function(t,e){return{combined:o(!1,f,u).calculate(t.segments,t.inverted,e.segments,e.inverted),inverted1:t.inverted,inverted2:e.inverted}},selectUnion:function(t){return{segments:l.union(t.combined,u),inverted:t.inverted1||t.inverted2}},selectIntersect:function(t){return{segments:l.intersect(t.combined,u),inverted:t.inverted1&&t.inverted2}},selectDifference:function(t){return{segments:l.difference(t.combined,u),inverted:t.inverted1&&!t.inverted2}},selectDifferenceRev:function(t){return{segments:l.differenceRev(t.combined,u),inverted:!t.inverted1&&t.inverted2}},selectXor:function(t){return{segments:l.xor(t.combined,u),inverted:t.inverted1!==t.inverted2}},polygon:function(t){return{regions:s(t.segments,f,u),inverted:t.inverted}},polygonFromGeoJSON:function(t){return c.toPolygon(n,t)},polygonToGeoJSON:function(t){return c.fromPolygon(n,f,t)},union:function(t,e){return h(t,e,n.selectUnion)},intersect:function(t,e){return h(t,e,n.selectIntersect)},difference:function(t,e){return h(t,e,n.selectDifference)},differenceRev:function(t,e){return h(t,e,n.selectDifferenceRev)},xor:function(t,e){return h(t,e,n.selectXor)}},"object"==typeof window&&(window.PolyBool=n),e.exports=n},{"./lib/build-log":250,"./lib/epsilon":251,"./lib/geojson":252,"./lib/intersecter":253,"./lib/segment-chainer":255,"./lib/segment-selector":256}],250:[function(t,e,r){e.exports=function(){var t,e=0,r=!1;function n(e,r){return t.list.push({type:e,data:r?JSON.parse(JSON.stringify(r)):void 0}),t}return t={list:[],segmentId:function(){return e++},checkIntersection:function(t,e){return n("check",{seg1:t,seg2:e})},segmentChop:function(t,e){return n("div_seg",{seg:t,pt:e}),n("chop",{seg:t,pt:e})},statusRemove:function(t){return n("pop_seg",{seg:t})},segmentUpdate:function(t){return n("seg_update",{seg:t})},segmentNew:function(t,e){return n("new_seg",{seg:t,primary:e})},segmentRemove:function(t){return n("rem_seg",{seg:t})},tempStatus:function(t,e,r){return n("temp_status",{seg:t,above:e,below:r})},rewind:function(t){return n("rewind",{seg:t})},status:function(t,e,r){return n("status",{seg:t,above:e,below:r})},vert:function(e){return e===r?t:(r=e,n("vert",{x:e}))},log:function(t){return"string"!=typeof t&&(t=JSON.stringify(t,!1," ")),n("log",{txt:t})},reset:function(){return n("reset")},selected:function(t){return n("selected",{segs:t})},chainStart:function(t){return n("chain_start",{seg:t})},chainRemoveHead:function(t,e){return n("chain_rem_head",{index:t,pt:e})},chainRemoveTail:function(t,e){return n("chain_rem_tail",{index:t,pt:e})},chainNew:function(t,e){return n("chain_new",{pt1:t,pt2:e})},chainMatch:function(t){return n("chain_match",{index:t})},chainClose:function(t){return n("chain_close",{index:t})},chainAddHead:function(t,e){return n("chain_add_head",{index:t,pt:e})},chainAddTail:function(t,e){return n("chain_add_tail",{index:t,pt:e})},chainConnect:function(t,e){return n("chain_con",{index1:t,index2:e})},chainReverse:function(t){return n("chain_rev",{index:t})},chainJoin:function(t,e){return n("chain_join",{index1:t,index2:e})},done:function(){return n("done")}}}},{}],251:[function(t,e,r){e.exports=function(t){"number"!=typeof t&&(t=1e-10);var e={epsilon:function(e){return"number"==typeof e&&(t=e),t},pointAboveOrOnLine:function(e,r,n){var i=r[0],a=r[1],o=n[0],s=n[1],l=e[0];return(o-i)*(e[1]-a)-(s-a)*(l-i)>=-t},pointBetween:function(e,r,n){var i=e[1]-r[1],a=n[0]-r[0],o=e[0]-r[0],s=n[1]-r[1],l=o*a+i*s;return!(l<t)&&!(l-(a*a+s*s)>-t)},pointsSameX:function(e,r){return Math.abs(e[0]-r[0])<t},pointsSameY:function(e,r){return Math.abs(e[1]-r[1])<t},pointsSam
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
var n=t("buffer"),i=n.Buffer;function a(t,e){for(var r in t)e[r]=t[r]}function o(t,e,r){return i(t,e,r)}i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?e.exports=n:(a(n,r),r.Buffer=o),o.prototype=Object.create(i.prototype),a(i,o),o.from=function(t,e,r){if("number"==typeof t)throw new TypeError("Argument must not be a number");return i(t,e,r)},o.alloc=function(t,e,r){if("number"!=typeof t)throw new TypeError("Argument must be a number");var n=i(t);return void 0!==e?"string"==typeof r?n.fill(e,r):n.fill(e):n.fill(0),n},o.allocUnsafe=function(t){if("number"!=typeof t)throw new TypeError("Argument must be a number");return i(t)},o.allocUnsafeSlow=function(t){if("number"!=typeof t)throw new TypeError("Argument must be a number");return n.SlowBuffer(t)}},{buffer:80}],280:[function(t,e,r){e.exports=i;var n=t("events").EventEmitter;function i(){n.call(this)}t("inherits")(i,n),i.Readable=t("readable-stream/lib/_stream_readable.js"),i.Writable=t("readable-stream/lib/_stream_writable.js"),i.Duplex=t("readable-stream/lib/_stream_duplex.js"),i.Transform=t("readable-stream/lib/_stream_transform.js"),i.PassThrough=t("readable-stream/lib/_stream_passthrough.js"),i.finished=t("readable-stream/lib/internal/streams/end-of-stream.js"),i.pipeline=t("readable-stream/lib/internal/streams/pipeline.js"),i.Stream=i,i.prototype.pipe=function(t,e){var r=this;function i(e){t.writable&&!1===t.write(e)&&r.pause&&r.pause()}function a(){r.readable&&r.resume&&r.resume()}r.on("data",i),t.on("drain",a),t._isStdio||e&&!1===e.end||(r.on("end",s),r.on("close",l));var o=!1;function s(){o||(o=!0,t.end())}function l(){o||(o=!0,"function"==typeof t.destroy&&t.destroy())}function c(t){if(u(),0===n.listenerCount(this,"error"))throw t}function u(){r.removeListener("data",i),t.removeListener("drain",a),r.removeListener("end",s),r.removeListener("close",l),r.removeListener("error",c),t.removeListener("error",c),r.removeListener("end",u),r.removeListener("close",u),t.removeListener("close",u)}return r.on("error",c),t.on("error",c),r.on("end",u),r.on("close",u),t.on("close",u),t.emit("pipe",r),t}},{events:181,inherits:226,"readable-stream/lib/_stream_duplex.js":282,"readable-stream/lib/_stream_passthrough.js":283,"readable-stream/lib/_stream_readable.js":284,"readable-stream/lib/_stream_transform.js":285,"readable-stream/lib/_stream_writable.js":286,"readable-stream/lib/internal/streams/end-of-stream.js":290,"readable-stream/lib/internal/streams/pipeline.js":292}],281:[function(t,e,r){"use strict";var n={};function i(t,e,r){r||(r=Error);var i=function(t){var r,n;function i(r,n,i){return t.call(this,function(t,r,n){return"string"==typeof e?e:e(t,r,n)}(r,n,i))||this}return n=t,(r=i).prototype=Object.create(n.prototype),r.prototype.constructor=r,r.__proto__=n,i}(r);i.prototype.name=r.name,i.prototype.code=t,n[t]=i}function a(t,e){if(Array.isArray(t)){var r=t.length;return t=t.map((function(t){return String(t)})),r>2?"one of ".concat(e," ").concat(t.slice(0,r-1).join(", "),", or ")+t[r-1]:2===r?"one of ".concat(e," ").concat(t[0]," or ").concat(t[1]):"of ".concat(e," ").concat(t[0])}return"of ".concat(e," ").concat(String(t))}i("ERR_INVALID_OPT_VALUE",(function(t,e){return'The value "'+e+'" is invalid for option "'+t+'"'}),TypeError),i("ERR_INVALID_ARG_TYPE",(function(t,e,r){var n,i,o,s;if("string"==typeof e&&(i="not ",e.substr(!o||o<0?0:+o,i.length)===i)?(n="must not be",e=e.replace(/^not /,"")):n="must be",function(t,e,r){return(void 0===r||r>t.length)&&(r=t.length),t.substring(r-e.length,r)===e}(t," argument"))s="The ".concat(t," ").concat(n," ").concat(a(e,"type"));else{var l=function(t,e,r){return"number"!=typeof r&&(r=0),!(r+e.length>t.length)&&-1!==t.indexOf(e,r)}(t,".")?"property":"argument";s='The "'.concat(t,'" ').concat(l," ").concat(n," ").concat(a(e,"type"))}return s+=". Received type ".concat(typeof r)}),TypeError),i("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF"),i("ERR_METHOD_NOT_IMPLEMENTED",(function(t){return"The "+t+" method is not implemented"})),i("ERR_STREAM_PREMATURE_CLOSE","Premature close"),i("ERR_STREAM_DESTROYED",(function(t){return"Can
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
"use strict";var e=t("base64-js"),n=t("ieee754");r.Buffer=a,r.SlowBuffer=function(t){+t!=t&&(t=0);return a.alloc(+t)},r.INSPECT_MAX_BYTES=50;function i(t){if(t>2147483647)throw new RangeError('The value "'+t+'" is invalid for option "size"');var e=new Uint8Array(t);return e.__proto__=a.prototype,e}function a(t,e,r){if("number"==typeof t){if("string"==typeof e)throw new TypeError('The "string" argument must be of type string. Received type number');return l(t)}return o(t,e,r)}function o(t,e,r){if("string"==typeof t)return function(t,e){"string"==typeof e&&""!==e||(e="utf8");if(!a.isEncoding(e))throw new TypeError("Unknown encoding: "+e);var r=0|f(t,e),n=i(r),o=n.write(t,e);o!==r&&(n=n.slice(0,o));return n}(t,e);if(ArrayBuffer.isView(t))return c(t);if(null==t)throw TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t);if(B(t,ArrayBuffer)||t&&B(t.buffer,ArrayBuffer))return function(t,e,r){if(e<0||t.byteLength<e)throw new RangeError('"offset" is outside of buffer bounds');if(t.byteLength<e+(r||0))throw new RangeError('"length" is outside of buffer bounds');var n;n=void 0===e&&void 0===r?new Uint8Array(t):void 0===r?new Uint8Array(t,e):new Uint8Array(t,e,r);return n.__proto__=a.prototype,n}(t,e,r);if("number"==typeof t)throw new TypeError('The "value" argument must not be of type number. Received type number');var n=t.valueOf&&t.valueOf();if(null!=n&&n!==t)return a.from(n,e,r);var o=function(t){if(a.isBuffer(t)){var e=0|u(t.length),r=i(e);return 0===r.length||t.copy(r,0,0,e),r}if(void 0!==t.length)return"number"!=typeof t.length||N(t.length)?i(0):c(t);if("Buffer"===t.type&&Array.isArray(t.data))return c(t.data)}(t);if(o)return o;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof t[Symbol.toPrimitive])return a.from(t[Symbol.toPrimitive]("string"),e,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t)}function s(t){if("number"!=typeof t)throw new TypeError('"size" argument must be of type number');if(t<0)throw new RangeError('The value "'+t+'" is invalid for option "size"')}function l(t){return s(t),i(t<0?0:0|u(t))}function c(t){for(var e=t.length<0?0:0|u(t.length),r=i(e),n=0;n<e;n+=1)r[n]=255&t[n];return r}function u(t){if(t>=2147483647)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+2147483647..toString(16)+" bytes");return 0|t}function f(t,e){if(a.isBuffer(t))return t.length;if(ArrayBuffer.isView(t)||B(t,ArrayBuffer))return t.byteLength;if("string"!=typeof t)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof t);var r=t.length,n=arguments.length>2&&!0===arguments[2];if(!n&&0===r)return 0;for(var i=!1;;)switch(e){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return D(t).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return R(t).length;default:if(i)return n?-1:D(t).length;e=(""+e).toLowerCase(),i=!0}}function h(t,e,r){var n=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(e>>>=0))return"";for(t||(t="utf8");;)switch(t){case"hex":return M(this,e,r);case"utf8":case"utf-8":return T(this,e,r);case"ascii":return k(this,e,r);case"latin1":case"binary":return A(this,e,r);case"base64":return w(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}function p(t,e,r){var n=t[e];t[e]=t[r],t[r]=n}function d(t,e,r,n,i){if(0===t.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),N(r=+r)&&(r=i?0:t.length-1),r<0&&(r=t.length+r),r>=t.length){if(i)return-1;r=t.length-1}else if(r<0){if(!i)return-1;r=0}if("string"==typeof e&&(e=a.from(e,n)),a.isBuffer(e))return 0===e.length?-1:m(t,e,r,n,i);if("number"==typeof e)return e&=255,"functio
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
e.exports=function(t){return null!=t&&(n(t)||function(t){return"function"==typeof t.readFloatLE&&"function"==typeof t.slice&&n(t.slice(0,0))}(t)||!!t._isBuffer)}},{}],238:[function(t,e,r){"use strict";e.exports=a,e.exports.isMobile=a,e.exports.default=a;var n=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i,i=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino|android|ipad|playbook|silk/i;function a(t){t||(t={});var e=t.ua;if(e||"undefined"==typeof navigator||(e=navigator.userAgent),e&&e.headers&&"string"==typeof e.headers["user-agent"]&&(e=e.headers["user-agent"]),"string"!=typeof e)return!1;var r=t.tablet?i.test(e):n.test(e);return!r&&t.tablet&&t.featureDetect&&navigator&&navigator.maxTouchPoints>1&&-1!==e.indexOf("Macintosh")&&-1!==e.indexOf("Safari")&&(r=!0),r}},{}],239:[function(t,e,r){"use strict";e.exports=function(t){for(var e,r=t.length,n=0;n<r;n++)if(((e=t.charCodeAt(n))<9||e>13)&&32!==e&&133!==e&&160!==e&&5760!==e&&6158!==e&&(e<8192||e>8205)&&8232!==e&&8233!==e&&8239!==e&&8287!==e&&8288!==e&&12288!==e&&65279!==e)return!1;return!0}},{}],240:[function(t,e,r){e.exports=function(t,e,r){return t*(1-r)+e*r}},{}],241:[function(t,e,r){var n=t("./normalize"),i=t("gl-mat4/create"),a=t("gl-mat4/clone"),o=t("gl-mat4/determinant"),s=t("gl-mat4/invert"),l=t("gl-mat4/transpose"),c={length:t("gl-vec3/length"),normalize:t("gl-vec3/normalize"),dot:t("gl-vec3/dot"),cross:t("gl-vec3/cross")},u=i(),f=i(),h=[0,0,0,0],p=[[0,0,0],[0,0,0],[0,0,0]],d=[0,0,0];function m(t,e,r,n,i){t[0]=e[0]*n+r[0]*i,t[1]=e[1]*n+r[1]*i,t[2]=e[2]*n+r[2]*i}e.exports=function(t,e,r,i,g,v){if(e||(e=[0,0,0]),r||(r=[0,0,0]),i||(i=[0,0,0]),g||(g=[0,0,0,1]),v||(v=[0,0,0,1]),!n(u,t))return!1;if(a(f,u),f[3]=0,f[7]=0,f[11]=0,f[15]=1,Math.abs(o(f)<1e-8))return!1;var y,x,b,_,w,T,k,A=u[3],M=u[7],S=u[11],E=u[12],L=u[13],C=u[14],P=u[15];if(0!==A||0!==M||0!==S){if(h[0]=A,h[1]=M,h[2]=S,h[3]=P,!s(f,f))return!1;l(f,f),y=g,b=f,_=(x=h)[0],w=x[1],T=x[2],k=x[3],y[0]=b[0]*_+b[4]*w+b[8]*T+b[12]*k,y[1]=b[1]*_+b[5]*w+b[9]*T+b[13]*k,y[2]=b[2]*_+b[6]*w+b[10]*T+b[14]*k,y[3]=b[3]*_+b[7]*w+b[11]*T+b[15]*k}else g[0]=g[1]=g[2]=0,g[3]=1;if(e[0]=E,e[1]=L,e[2]=C,function(t,e){t[0][0]=e[0],t[0][1]=e[1],t[0][2]=e[2],t[1][0]=e[4],t[1][1]=e[5],t[1][2]=e[6],t[2][0]=e[8],t[2][1]=e[9],t[2][2]=e[10]}(p,u),r[0]=c.length(p[0]),c.normalize(p[0],p[0]),i[0]=c.dot(p[0],p[1]),m(p[1],p[1],p[0],1,-i[0]),r[1]=c.length(p[1]),c.normalize(p[1],p[1]),i[0]/=r[1],i[1]=c.dot(p[0],p[2]),m(p[2],p[2],p[0],1,-i[1]),i[2]=c.dot(p[1],p[2]),m(p[2],p[2],p[1],1,-i[2]),r[2]=c.length(p[2]),c.normalize(p[2],p[2]),i[1]/=r[2],i[2]/=r[2],c.cross(d,p[1],p[2]),c.dot(p[0],d)<0)for(var I=0;I<3;I++)r[I]*=-1,p[I][0]*=-1,p[I][1]*=-1,p[I][2]*=-1;return v[0]=.5*Math.sqrt(Math.max(1+p[0][0]-p[1][1]-p[2][2],0)),v[1]=.5*Math.sqrt(Math.max(1-p[0][0]+p[1][1]-p[2][2],0)),v[2]=.5*Math.sqrt(Math.max(1-p[0][0]-p[1][1]+p[2][2],0)),v[3]=.5*Math.sqrt(Math.max(1+p[0][0]+p[1][1]+p[2][2],0)),p[2][1]>p[1][2]&&(v[0]=-v[0]),p[0][2]>p[2][0]&&(v[1]=-v[1]),p[1][0]>p[0][1]&&(v[2]=-v[2]),!0}},{"./normalize":242,"gl-mat4/clone":92,"gl-mat4/create":93,"gl-mat4/determinant":94,"gl-mat4/invert":98,"gl-mat4/transpose":109,"gl-vec3/cross":157,"gl-vec3/dot":162,"gl-vec3/length":172,"gl-vec3/normalize":179}],242:[function(t,e,r){e.exports=function(t,e){var r=e[15];if(0===r)return!1;for(var n=1/r,i=0;i<16;i++)t[i]=e[i]*n;return!0}},{}],243:[function(t,e,r){var n=t("gl-vec3/lerp"),i=t("mat4-recompose"),a=t("mat4-decompose"),o=t("gl-mat4/determinant"),s=t("quat-slerp"),l=f(),c=f(),u=f();function f(){return{translate:h(),scale:h(1),skew:h(),pe
/*!
* pad-left <https://github.com/jonschlinkert/pad-left>
*
* Copyright (c) 2014-2015, Jon Schlinkert.
* Licensed under the MIT license.
*/
"use strict";var n=t("repeat-string");e.exports=function(t,e,r){return n(r=void 0!==r?r+"":" ",e)+t}},{"repeat-string":277}],265:[function(t,e,r){e.exports=function(t,e){e||(e=[0,""]),t=String(t);var r=parseFloat(t,10);return e[0]=r,e[1]=t.match(/[\d.\-\+]*\s*(.*)/)[1]||"",e}},{}],266:[function(t,e,r){"use strict";e.exports=function(t,e){for(var r=0|e.length,i=t.length,a=[new Array(r),new Array(r)],o=0;o<r;++o)a[0][o]=[],a[1][o]=[];for(o=0;o<i;++o){var s=t[o];a[0][s[0]].push(s),a[1][s[1]].push(s)}var l=[];for(o=0;o<r;++o)a[0][o].length+a[1][o].length===0&&l.push([o]);function c(t,e){var r=a[e][t[e]];r.splice(r.indexOf(t),1)}function u(t,r,i){for(var o,s,l,u=0;u<2;++u)if(a[u][r].length>0){o=a[u][r][0],l=u;break}s=o[1^l];for(var f=0;f<2;++f)for(var h=a[f][r],p=0;p<h.length;++p){var d=h[p],m=d[1^f];n(e[t],e[r],e[s],e[m])>0&&(o=d,s=m,l=f)}return i||o&&c(o,l),s}function f(t,r){var i=a[r][t][0],o=[t];c(i,r);for(var s=i[1^r];;){for(;s!==t;)o.push(s),s=u(o[o.length-2],s,!1);if(a[0][t].length+a[1][t].length===0)break;var l=o[o.length-1],f=t,h=o[1],p=u(l,f,!0);if(n(e[l],e[f],e[h],e[p])<0)break;o.push(t),s=u(l,f)}return o}function h(t,e){return e[1]===e[e.length-1]}for(o=0;o<r;++o)for(var p=0;p<2;++p){for(var d=[];a[p][o].length>0;){a[0][o].length;var m=f(o,p);h(0,m)?d.push.apply(d,m):(d.length>0&&l.push(d),d=m)}d.length>0&&l.push(d)}return l};var n=t("compare-angle")},{"compare-angle":54}],267:[function(t,e,r){"use strict";e.exports=function(t,e){for(var r=n(t,e.length),i=new Array(e.length),a=new Array(e.length),o=[],s=0;s<e.length;++s){var l=r[s].length;a[s]=l,i[s]=!0,l<=1&&o.push(s)}for(;o.length>0;){var c=o.pop();i[c]=!1;var u=r[c];for(s=0;s<u.length;++s){var f=u[s];0==--a[f]&&o.push(f)}}var h=new Array(e.length),p=[];for(s=0;s<e.length;++s)if(i[s]){c=p.length;h[s]=c,p.push(e[s])}else h[s]=-1;var d=[];for(s=0;s<t.length;++s){var m=t[s];i[m[0]]&&i[m[1]]&&d.push([h[m[0]],h[m[1]]])}return[d,p]};var n=t("edges-to-adjacency-list")},{"edges-to-adjacency-list":66}],268:[function(t,e,r){"use strict";e.exports=function(t,e){var r=c(t,e);t=r[0];for(var f=(e=r[1]).length,h=(t.length,n(t,e.length)),p=0;p<f;++p)if(h[p].length%2==1)throw new Error("planar-graph-to-polyline: graph must be manifold");var d=i(t,e);var m=(d=d.filter((function(t){for(var r=t.length,n=[0],i=0;i<r;++i){var a=e[t[i]],l=e[t[(i+1)%r]],c=o(-a[0],a[1]),u=o(-a[0],l[1]),f=o(l[0],a[1]),h=o(l[0],l[1]);n=s(n,s(s(c,u),s(f,h)))}return n[n.length-1]>0}))).length,g=new Array(m),v=new Array(m);for(p=0;p<m;++p){g[p]=p;var y=new Array(m),x=d[p].map((function(t){return e[t]})),b=a([x]),_=0;t:for(var w=0;w<m;++w)if(y[w]=0,p!==w){for(var T=(H=d[w]).length,k=0;k<T;++k){var A=b(e[H[k]]);if(0!==A){A<0&&(y[w]=1,_+=1);continue t}}y[w]=1,_+=1}v[p]=[_,p,y]}v.sort((function(t,e){return e[0]-t[0]}));for(p=0;p<m;++p){var M=(y=v[p])[1],S=y[2];for(w=0;w<m;++w)S[w]&&(g[w]=M)}var E=function(t){for(var e=new Array(t),r=0;r<t;++r)e[r]=[];return e}(m);for(p=0;p<m;++p)E[p].push(g[p]),E[g[p]].push(p);var L={},C=u(f,!1);for(p=0;p<m;++p)for(T=(H=d[p]).length,w=0;w<T;++w){var P=H[w],I=H[(w+1)%T],O=Math.min(P,I)+":"+Math.max(P,I);if(O in L){var z=L[O];E[z].push(p),E[p].push(z),C[P]=C[I]=!0}else L[O]=p}function D(t){for(var e=t.length,r=0;r<e;++r)if(!C[t[r]])return!1;return!0}var R=[],F=u(m,-1);for(p=0;p<m;++p)g[p]!==p||D(d[p])?F[p]=-1:(R.push(p),F[p]=0);r=[];for(;R.length>0;){var B=R.pop(),N=E[B];l(N,(function(t,e){return t-e}));var j,U=N.length,V=F[B];if(0===V){var H=d[B];j=[H]}for(p=0;p<U;++p){var q=N[p];if(!(F[q]>=0))if(F[q]=1^V,R.push(q),0===V)D(H=d[q])||(H.reverse(),j.push(H))}0===V&&r.push(j)}return r};var n=t("edges-to-adjacency-list"),i=t("planar-dual"),a=t("point-in-big-polygon"),o=t("two-product"),s=t("robust-sum"),l=t("uniq"),c=t("./lib/trim-leaves");function u(t,e){for(var r=new Array(t),n=0;n<t;++n)r[n]=e;return r}},{"./lib/trim-leaves":267,"edges-to-adjacency-list":66,"planar-dual":266,"point-in-big-polygon":269,"robust-sum":289,"two-product":306,uniq:310}],269:[function(t,e,r){e.exports=function(t){for(var e=t.length,r=[],a=[],s=0;s<e;++s)for(var u=t[s],f=u.length,h=f-1,p=0;p<f;h=p++){var d
/*!
* repeat-string <https://github.com/jonschlinkert/repeat-string>
*
* Copyright (c) 2014-2015, Jon Schlinkert.
* Licensed under the MIT License.
*/
"use strict";var n,i="";e.exports=function(t,e){if("string"!=typeof t)throw new TypeError("expected a string");if(1===e)return t;if(2===e)return t+t;var r=t.length*e;if(n!==t||void 0===n)n=t,i="";else if(i.length>=r)return i.substr(0,r);for(;r>i.length&&e>1;)1&e&&(i+=t),e>>=1,t+=t;return i=(i+=t).substr(0,r)}},{}],278:[function(t,e,r){(function(t){(function(){e.exports=t.performance&&t.performance.now?function(){return performance.now()}:Date.now||function(){return+new Date}}).call(this)}).call(this,void 0!==n?n:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],279:[function(t,e,r){"use strict";e.exports=function(t){for(var e=t.length,r=t[t.length-1],n=e,i=e-2;i>=0;--i){var a=r,o=t[i];(l=o-((r=a+o)-a))&&(t[--n]=r,r=l)}var s=0;for(i=n;i<e;++i){var l;a=t[i];(l=(o=r)-((r=a+o)-a))&&(t[s++]=l)}return t[s++]=r,t.length=s,t}},{}],280:[function(t,e,r){"use strict";var n=t("two-product"),i=t("robust-sum"),a=t("robust-scale"),o=t("robust-compress");function s(t,e,r,n){return function(e){return n(t(r(e[0][0],e[1][1]),r(-e[0][1],e[1][0])))}}function l(t,e,r,n){return function(i){return n(t(e(t(r(i[1][1],i[2][2]),r(-i[1][2],i[2][1])),i[0][0]),t(e(t(r(i[1][0],i[2][2]),r(-i[1][2],i[2][0])),-i[0][1]),e(t(r(i[1][0],i[2][1]),r(-i[1][1],i[2][0])),i[0][2]))))}}function c(t,e,r,n){return function(i){return n(t(t(e(t(e(t(r(i[2][2],i[3][3]),r(-i[2][3],i[3][2])),i[1][1]),t(e(t(r(i[2][1],i[3][3]),r(-i[2][3],i[3][1])),-i[1][2]),e(t(r(i[2][1],i[3][2]),r(-i[2][2],i[3][1])),i[1][3]))),i[0][0]),e(t(e(t(r(i[2][2],i[3][3]),r(-i[2][3],i[3][2])),i[1][0]),t(e(t(r(i[2][0],i[3][3]),r(-i[2][3],i[3][0])),-i[1][2]),e(t(r(i[2][0],i[3][2]),r(-i[2][2],i[3][0])),i[1][3]))),-i[0][1])),t(e(t(e(t(r(i[2][1],i[3][3]),r(-i[2][3],i[3][1])),i[1][0]),t(e(t(r(i[2][0],i[3][3]),r(-i[2][3],i[3][0])),-i[1][1]),e(t(r(i[2][0],i[3][1]),r(-i[2][1],i[3][0])),i[1][3]))),i[0][2]),e(t(e(t(r(i[2][1],i[3][2]),r(-i[2][2],i[3][1])),i[1][0]),t(e(t(r(i[2][0],i[3][2]),r(-i[2][2],i[3][0])),-i[1][1]),e(t(r(i[2][0],i[3][1]),r(-i[2][1],i[3][0])),i[1][2]))),-i[0][3]))))}}function u(t,e,r,n){return function(i){return n(t(t(e(t(t(e(t(e(t(r(i[3][3],i[4][4]),r(-i[3][4],i[4][3])),i[2][2]),t(e(t(r(i[3][2],i[4][4]),r(-i[3][4],i[4][2])),-i[2][3]),e(t(r(i[3][2],i[4][3]),r(-i[3][3],i[4][2])),i[2][4]))),i[1][1]),e(t(e(t(r(i[3][3],i[4][4]),r(-i[3][4],i[4][3])),i[2][1]),t(e(t(r(i[3][1],i[4][4]),r(-i[3][4],i[4][1])),-i[2][3]),e(t(r(i[3][1],i[4][3]),r(-i[3][3],i[4][1])),i[2][4]))),-i[1][2])),t(e(t(e(t(r(i[3][2],i[4][4]),r(-i[3][4],i[4][2])),i[2][1]),t(e(t(r(i[3][1],i[4][4]),r(-i[3][4],i[4][1])),-i[2][2]),e(t(r(i[3][1],i[4][2]),r(-i[3][2],i[4][1])),i[2][4]))),i[1][3]),e(t(e(t(r(i[3][2],i[4][3]),r(-i[3][3],i[4][2])),i[2][1]),t(e(t(r(i[3][1],i[4][3]),r(-i[3][3],i[4][1])),-i[2][2]),e(t(r(i[3][1],i[4][2]),r(-i[3][2],i[4][1])),i[2][3]))),-i[1][4]))),i[0][0]),e(t(t(e(t(e(t(r(i[3][3],i[4][4]),r(-i[3][4],i[4][3])),i[2][2]),t(e(t(r(i[3][2],i[4][4]),r(-i[3][4],i[4][2])),-i[2][3]),e(t(r(i[3][2],i[4][3]),r(-i[3][3],i[4][2])),i[2][4]))),i[1][0]),e(t(e(t(r(i[3][3],i[4][4]),r(-i[3][4],i[4][3])),i[2][0]),t(e(t(r(i[3][0],i[4][4]),r(-i[3][4],i[4][0])),-i[2][3]),e(t(r(i[3][0],i[4][3]),r(-i[3][3],i[4][0])),i[2][4]))),-i[1][2])),t(e(t(e(t(r(i[3][2],i[4][4]),r(-i[3][4],i[4][2])),i[2][0]),t(e(t(r(i[3][0],i[4][4]),r(-i[3][4],i[4][0])),-i[2][2]),e(t(r(i[3][0],i[4][2]),r(-i[3][2],i[4][0])),i[2][4]))),i[1][3]),e(t(e(t(r(i[3][2],i[4][3]),r(-i[3][3],i[4][2])),i[2][0]),t(e(t(r(i[3][0],i[4][3]),r(-i[3][3],i[4][0])),-i[2][2]),e(t(r(i[3][0],i[4][2]),r(-i[3][2],i[4][0])),i[2][3]))),-i[1][4]))),-i[0][1])),t(e(t(t(e(t(e(t(r(i[3][3],i[4][4]),r(-i[3][4],i[4][3])),i[2][1]),t(e(t(r(i[3][1],i[4][4]),r(-i[3][4],i[4][1])),-i[2][3]),e(t(r(i[3][1],i[4][3]),r(-i[3][3],i[4][1])),i[2][4]))),i[1][0]),e(t(e(t(r(i[3][3],i[4][4]),r(-i[3][4],i[4][3])),i[2][0]),t(e(t(r(i[3][0],i[4][4]),r(-i[3][4],i[4][0])),-i[2][3]),e(t(r(i[3][0],i[4][3]),r(-i[3][3],i[4][0])),i[2][4]))),-i[1][1])),t(e(t(e(t(r(i[3][1],i[4][4]),r(-i[3][4],i[4][1])),i[2][0]),t(e(t(r(i[3][0],i[4][4]),r(-i[3][4],i[4][0])),-i[2][1]),e(t(r(i[3][0],i[4][1]),r(-i[3][1],i[4][0])),i[2][
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
</style>
<style type="text/css">
code {
white-space: pre;
}
.sourceCode {
overflow: visible;
}
</style>
<style type="text/css" data-origin="pandoc">
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ background-color: #f8f8f8; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ef2929; }
code span.an { color: #8f5902; font-weight: bold; font-style: italic; }
code span.at { color: #204a87; }
code span.bn { color: #0000cf; }
code span.cf { color: #204a87; font-weight: bold; }
code span.ch { color: #4e9a06; }
code span.cn { color: #8f5902; }
code span.co { color: #8f5902; font-style: italic; }
code span.cv { color: #8f5902; font-weight: bold; font-style: italic; }
code span.do { color: #8f5902; font-weight: bold; font-style: italic; }
code span.dt { color: #204a87; }
code span.dv { color: #0000cf; }
code span.er { color: #a40000; font-weight: bold; }
code span.ex { }
code span.fl { color: #0000cf; }
code span.fu { color: #204a87; font-weight: bold; }
code span.im { }
code span.in { color: #8f5902; font-weight: bold; font-style: italic; }
code span.kw { color: #204a87; font-weight: bold; }
code span.op { color: #ce5c00; font-weight: bold; }
code span.ot { color: #8f5902; }
code span.pp { color: #8f5902; font-style: italic; }
code span.sc { color: #ce5c00; font-weight: bold; }
code span.ss { color: #4e9a06; }
code span.st { color: #4e9a06; }
code span.va { color: #000000; }
code span.vs { color: #4e9a06; }
code span.wa { color: #8f5902; font-weight: bold; font-style: italic; }
</style>
<script>
// apply pandoc div.sourceCode style to pre.sourceCode instead
(function() {
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].ownerNode.dataset["origin"] !== "pandoc") continue;
try { var rules = sheets[i].cssRules; } catch (e) { continue; }
var j = 0;
while (j < rules.length) {
var rule = rules[j];
// check if there is a div.sourceCode rule
if (rule.type !== rule.STYLE_RULE || rule.selectorText !== "div.sourceCode") {
j++;
continue;
}
var style = rule.style.cssText;
// check if color or background-color is set
if (rule.style.color === '' && rule.style.backgroundColor === '') {
j++;
continue;
}
// replace div.sourceCode by a pre.sourceCode rule
sheets[i].deleteRule(j);
sheets[i].insertRule('pre.sourceCode{' + style + '}', j);
}
}
})();
</script>
<style type="text/css">
.main-container {
max-width: 940px;
margin-left: auto;
margin-right: auto;
}
img {
max-width:100%;
}
.tabbed-pane {
padding-top: 12px;
}
.html-widget {
margin-bottom: 20px;
}
button.code-folding-btn:focus {
outline: none;
}
summary {
display: list-item;
}
details > summary > p:only-child {
display: inline;
}
pre code {
padding: 0;
}
</style>
<!-- tabsets -->
<style type="text/css">
.tabset-dropdown > .nav-tabs {
display: inline-table;
max-height: 500px;
min-height: 44px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
}
.tabset-dropdown > .nav-tabs > li.active:before, .tabset-dropdown > .nav-tabs.nav-tabs-open:before {
content: "\e259";
font-family: 'Glyphicons Halflings';
display: inline-block;
padding: 10px;
border-right: 1px solid #ddd;
}
.tabset-dropdown > .nav-tabs.nav-tabs-open > li.active:before {
content: "\e258";
font-family: 'Glyphicons Halflings';
border: none;
}
.tabset-dropdown > .nav-tabs > li.active {
display: block;
}
.tabset-dropdown > .nav-tabs > li > a,
.tabset-dropdown > .nav-tabs > li > a:focus,
.tabset-dropdown > .nav-tabs > li > a:hover {
border: none;
display: inline-block;
border-radius: 4px;
background-color: transparent;
}
.tabset-dropdown > .nav-tabs.nav-tabs-open > li {
display: block;
float: none;
}
.tabset-dropdown > .nav-tabs > li {
display: none;
}
</style>
<!-- code folding -->
<style type="text/css">
#TOC {
margin: 25px 0px 20px 0px;
}
@media (max-width: 768px) {
#TOC {
position: relative;
width: 100%;
}
}
@media print {
.toc-content {
float: right;
}
}
.toc-content {
padding-left: 30px;
padding-right: 40px;
}
div.main-container {
max-width: 1200px;
}
div.tocify {
width: 20%;
max-width: 260px;
max-height: 85%;
}
@media (min-width: 768px) and (max-width: 991px) {
div.tocify {
width: 25%;
}
}
@media (max-width: 767px) {
div.tocify {
width: 100%;
max-width: none;
}
}
.tocify ul, .tocify li {
line-height: 20px;
}
.tocify-subheader .tocify-item {
font-size: 0.90em;
}
.tocify .list-group-item {
border-radius: 0px;
}
</style>
</head>
<body>
<div class="container-fluid main-container">
<!-- setup 3col/9col grid for toc_float and main content -->
<div class="row">
<div class="col-xs-12 col-sm-4 col-md-3">
<div id="TOC" class="tocify">
</div>
</div>
<div class="toc-content col-xs-12 col-sm-8 col-md-9">
<div id="header">
<h1 class="title toc-ignore">IQ Mini 4489 Probabilities Report</h1>
<h4 class="date">2024-12-25</h4>
</div>
<style>
body {
font-size: 11pt;
margin: 1in;
}
a {
color: #3498db;
}
.toc {
background-color: #34495e;
padding: 1rem;
border-radius: 5px;
}
h1, h2, h3, h4, h5, h6 {
color: #ecf0f1;
}
img {
display: block;
margin-left: auto;
margin-right: auto;
max-width: 80%;
}
</style>
<div id="introduction" class="section level2">
<h2>Introduction</h2>
<div class="float">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAGkCAYAAADJzkGPAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF7sfQeAXFd57j9lZ2e2d0mr3iXbsiz3AhgbA7YxCWAn1EBC8iCEJLwACSXhhZAAISQYQhxiYkhoDsUmFIPBGNsYF1xkWc3q2pV2pe29T33f9597Zu+OZqVdaSSvrXPt1czccu4532n/d/5yAiMT8UwoFJJgRswRSHtfvI9McOpve5u97LsaCAQkk7EJ5X1sxieZVqGPQuatUGmxjIXGrVB5K2S+bDkLXacuvRcXAnO57RYyb3O51uZyOV3eTq7lFBK3QqZ1cqWZ/qmzJW+FKqedlwuVXiFlhrkuA07fCk/uSiHr4ORykP8pm6989WGl9NlK/Wk8mEqlJDCeTIGABH0EJCepTH4ikO/F5AwF4h8QyvODcSpnC5m3QqVlBoDC4laovBWyPm05T6X+3LMvfgTmctstZN7mck3O5XK6vJ1cyykkboVM6+RKM/1TZ0veClVOOy8XKr1CygxzXQacvhWe3JVC1sHJ5SD/UzZf+eojHw/In8rUs1RzpNIZCVPzodqPgCEe3ofv7qxqJCdd737f2YAwO7PlQvmza9LKf+3kzxYyb4VJi2UpPG6FyVsh8zVZzpOvPffk2YDAXG67hczbXK7LuVxOl7eTazmFxK2QaZ1caaZ/6mzJW2HKOTkvFya9QskM+Vbbp6/z2VwpZDln896Z3DtX82bydTyZfKb6AltC2lVlJC357atmgtVpvqdQ6qhCZ3Ou5qvQ5XTpOQQcAlMRcH3/xdMiXF2+eOrydJRkrraPuZqvQtfB2VLOQuP2QksvLPT5gG7lWM1HblGmsjN7/zQWWrkPz/r36WPAs87KlAfmar5OrVTuaYeAQ+BECLi+fyKEXjjXXV2+cOrq+cjpXG0fczVfz0cduXfOAQQsLZihCiTXZKvgGpBCMddCpVPoKjqd+TrVtE/1+Vys5np6ufl1v1/YCBSivRUijelQLFTahUpnunyeyvlC5q2QabFMhUyvkGmdCt75np2reSt0vuZyeoXOW756PplzpzNfp5r2qT5/MnjM5pm5nL+5nDeL8ankcbpng8IoVwVUYxSKoRcqndk00Jncezrzdappn+rzueWf6+nl5tf9fmEjUIj2Vog0pkOxUGkXKp3p8nkq5wuZt0KmxTIVMr1CpnUqeOd7dq7mrdD5msvpFTpv+er5ZM6dznydatqn+vzJ4DGbZ+Zy/uZy3izGp5LH6Z4tuAZkNg3C3esQcAg4BBwCDgGHgEPAIeAQcAicXQiEbXGtEuTEviDmiQIqTc4uxF1pHQIOAYeAQ8Ah4BBwCDgEHAIvZARm6PthizjFkxzWV04D8kKufJd3h4BDwCHgEHAIOAQcAg4Bh8ALDIGsBmTSDyR/LOKM7vHBPSvyX3+Bldtl1yHgEHAIOAQcAg4Bh4BDwCHgECgAArMMiuU0IAXA3CXhEHAIOAQcAg4Bh4BDwCHgEHAIzBCBSQ3ICR5wmo8TAOQuOwQcAg4Bh4BDwCHgEHAIOATOQgRm6RLiNCBnYRtxRXYIOAQcAg4Bh4BDwCHgEHAIPG8IZDUgs9VwBAQ7qOPIOA7zvFWee7FDwCHgEHAIOAQcAg4Bh4BD4IwjMK3Th+EHksMPTvtO6GccAPdCh4BDwCHgEHAIOAQcAg4Bh4BD4AWDwIx9QHJL5DQfuYi43w4Bh4BDwCHgEHAIOAQcAg6BswCBaZ0+ZrbDx8zuOgtwdEV0CDgEHAIOAYeAQ8Ah4BBwCDgETj8CjoCcfozdGxwCDgGHgEPAIeAQcAg4BBwCDgEPAUdAXFNwCDgEHAIOAYeAQ8Ah4BBwCDgEzhgCjoCcMajdixwCDgGHgEPAIeAQcAg4BBwCDgFHQFwbcAg4BBwCDgGHgEPAIeAQcAg4BM4YAo6AnDGo3YscAg4Bh4BDwCHgEHAIOAQcAg4BR0BcG3AIOAQcAg4Bh4BDwCHgEHAIOATOGAKOgJwxqN2LHAIOAYeAQ8Ah4BBwCDgEHAIOAUdAXBtwCDgEHAIOAYeAQ8Ah4BBwCDgEzhgCjoCcMajdixwCDgGHgEPAIeAQcAg4BBwCDgFHQFwbcAg4BBwCDgGHgEPAIeAQcAg4BM4YAo6AnDGo3YscAg4Bh4BDwCHgEHAIOAQcAg4BR0BcG3AIOAQcAg4Bh4BDwCHgEHAIOATOGAKOgJwxqN2LHAIOAYeAQ8Ah4BBwCDgEHAIOAUdAXBtwCDgEHAIOAYeAQ8Ah4BBwCDgEzhgC4TP2Jvcih4BDwCHgEHAIFBCBTCAtgQwTDHqfUxPPBMxvfpr7vE97Hpe9ryJMB+n5jwzS5ZG9x7uor9Tz9n67ljfdnd4DOc/Z9Kde5a+p+WD53OEQcAg4BF5MCDgC8mKqTVcWh4BDwCFwViHgEQTLCHxlt+TDnrIkRD/99+G7/uY/GU/Q927QU757C/Y15z0FS9cl5BBwCDgEXiAIOALyAqkol02HgEPAIeAQmIpAIMsyPJoADYYlDFMJyLEaBD+xyGo0LDNRbYh511QSAo0LL2UJRNAoTvRW/525Ggx/vvGMfc/U4vh+HZvfaW91FxwCDgGHwAsQATfKvQArzWXZIeAQcAg4BCYRoECvf3lNlYx5ljXBsk8pkcgBMUtKci6Yn4Z8TI/7bHUluW+fPmV3xSHgEHAIvNgQcBqQF1uNuvI4BBwCDoGzBoFJod9qFax2wk847Hf6jJhjUvjX+5W8mCOrDZmCoUc+vHv1kpdEfhph1/ZyfUT8ic6WsEzJkPvhEHAIOARe0Ag4AvKCrj6XeYeAQ8AhcDYjYAT8TMAT+Ke1bZpKVPKTBuI4SRh8Vlg4j/T9DOWYBPgcb7DEgzf4f9s6sg868nE2t1pXdoeAQ0DEERDXChwCDgGHgEPgBYnApNZjuuxnpvhbWKKSgfoiyyF82g9/KsdwDP+JY9QkJB5INcsr/ARj8sGMd8OJ8z1dedx5h4BDwCHw4kDAEZAXRz26UjgEHAIOgbMOgawzeLbkfmYwSQJyFSP5uIQfvGPIBy4yNT9pyQf2scTiRG/Kl4o75xBwCDgEXvwIOCf0F38duxI6BBwCDoEXJQKqUEjjH/wFAkbYD+hJaD4yHgHxrsMVXc95lw2jwC18CncrPvyuqZgk8IWmVcYsy9w3eclLXa8z9lbWER43HvsbaQRN/jKZFG5IwVhrMgXNl5f/bL6Zj1kc/udONo1ZvM7d6hBwCDgETgkBR0BOCT73sEPAIeAQcAg8HwgY8gFTqiCoBYT3dJpEIGVIBi7itB5B70symZSQ9RWhM7r+effwC/lAGg+lPH8Pdevgd/wl+d388TQohO8UqY0hN0xNhX+QDRIScgr9iTwwf7xm88PfPApFPGw6mqg7HAIOAYfAHEfAmWDN8Qpy2XMIOAQcAg6BYxFQcyfdCZ37kRvCkcF3Cvn2Uz0z8A+F83A47F0jkzDsQCkA/omPJiSdSEt3X68M9Q9IV3uf9PT0yKGm/VJcXCwJaCxGR0flcGuLlNdWy0VXXi7nX7BR6qrKpay0RKLFYUnh3SG8R71LDAcxmhnmB6Qm6JGfTAp5DoYmSROISCgUUoJiyYlfI3JsyaeeyUc88p07UTruukPAIeAQOJMIOAJyJtF273IIOAQcAg6BwiEATUNazZcMqbCCe8BqOmh+BVJABUYK90VAEjyKIBkQj66OPmk51CqjAyMy0D8oe/bskUQiIROjKRno65eR4X4lLSMjYzIRj0silZRo94iMjz0uPUf6pKq8RKqqKmXThRulcVGtkhkqNqh0YfokOgGaXnmcRz/x22ps+Gm1I/7PkyUQsyEuhasEl5JDwCHgEJg9AoF4IpUJhdQ6dvZP5zzBQbNQtqcnOwAfrxCFzFuh0mJ+C41bofJWyHzZch6vftw1h8BcbruFzNtcrum5XM7cvHGMSkHSt2OVGkP55iHykiQE/gmOswQdXwZ7hmXfnv2ydfNW6Whpl9HhEWk61CwVFRVSEo2qpqMoCI1GKiWlJTGh6VYwXaTXB4aHJBwpks62LpmYmJC
<div class="figcaption">IQ Mini 4489</div>
</div>
<div id="game" class="section level3">
<h3>Game</h3>
<style>
.z {
background-color: purple;
}
.x {
background-color: orange;
}
.y {
background-color: green;
}
td {
padding: 3rem;
}
img {
max-width: 600px;
}
table {
font-size: 3rem; border-collapse: collapse;
margin: 2rem auto;
}
</style>
<div id="table-container">
<table>
<tr>
<td class="x">
x
</td>
<td class="x">
x
</td>
<td>
o
</td>
<td class="y">
y
</td>
<td class="y">
y
</td>
</tr>
<tr>
<td class="x">
x
</td>
<td class="x">
x
</td>
<td class="x">
x
</td>
<td class="x">
x
</td>
<td class="y">
y
</td>
</tr>
<tr>
<td>
o
</td>
<td class="x">
x
</td>
<td class="z">
z
</td>
<td class="z">
z
</td>
<td class="y">
y
</td>
</tr>
<tr>
<td class="z">
z
</td>
<td class="x">
x
</td>
<td class="z">
z
</td>
<td>
o
</td>
<td class="y">
y
</td>
</tr>
<tr>
<td class="z">
z
</td>
<td class="z">
z
</td>
<td class="z">
z
</td>
<td class="y">
y
</td>
<td class="y">
y
</td>
</tr>
</table>
<p>Its a 5x5 grid of holes, connected as shown in the diagram. Each
colored path contains one peg which can be moved around to any other
square with the same color. The point of the game is to fit the 6
uniquely shaped pieces in the puzzle such that all of them fit (and
subsequently fill up the entire matrix).</p>
</div>
<div id="pieces" class="section level3">
<h3>Pieces</h3>
<p>Very similar to tetris:</p>
<div class="float">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAeACAYAAAAvokrGAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF7s3duPZVmeH/R17nHJyqyq6aG7h+62jMR4gAEz2LLHQMsCBvvBskbzAA/zYAshYSGQsCzmAR54QuIPGBlzG8wDBiHxAIwBSzAPCLAlzwX5gXEPWGo3pfZ4uqq7qzIzIs5981078mRFZ9e1d5yT+5z47KpQZNzWXvuz1tln7fVbl0GTozgIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBA4OgFhkd/BS6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBFoBAWAVgQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAiciIAB8IgXpMggQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQICAArA4QIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEDgRAQEgE+kIF0GAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEBIDVAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECJyIgADwiRSkyyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgIAAsDpAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBExEQAD6RgnQZBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQEABWBwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIHAiAgLAJ1KQLoMAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQICwOoAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIETkRAAPhECtJlECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAQABYHSBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMCJCAgAn0hBugwCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgIAKsDBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQOBEBAeATKUiXQYAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQFgdYAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQInIiAAfCIF6TIIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAgAKwOECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBA4EQEBIBPpCBdBgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBASA1QECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAiciIAA8IkUpMsgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQICAALA6QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgRMREAA+kYJ0GQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBAAVgcIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBwIgICwCdSkC6DAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECAsDqAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBE5EQAD4RArSZRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQEAAWB0gQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAiQgIAJ9IQboMAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQICACrAwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEDgRAQHgEylIl0GAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEBYHWAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECJyIgAHwiBekyCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgIACsDhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQOBEBASAT6QgXQYBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQEgNUBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQInIiAAPCJFKTLIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAgACwOkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIETERAAPpGCdBkECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAQAFYHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgcCICAsAnUpAugwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgLA6gABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgROREAA+EQK0mUQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBAAFgdIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwIkICACfSEG6DAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECAgAqwMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBA4EQEB4BMpSJdBgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAWB1gAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAiciIAB8IgXpMggQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQICAArA4QIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEDgRAQEgE+kIF0GAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEBIDVAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECJyIgADwiRSkyyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgIAAsDpAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBExEQAD6RgnQZBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQEABWBwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIHAiAgLAJ1KQLoMAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQICwOoAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIETkRAAPhECtJlECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAQABYHSBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMCJCAgAn0hBugwCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgIAKsDBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQOBEBAeATKUiXQYAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQFgdYAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQInIiAAfCIF6TIIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAgAKwOECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBA4EQEBIBPpCBdBgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBASA1QECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAiciIAA8IkUpMsgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQICAALA6QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgRMREAA+kYJ0GQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBAAVgcIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBwIgICwCdSkC6DAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECAsDqAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBE5EQAD4RArSZRAgQIAAAQIECBAgQIAAAQI
<div class="figcaption">Tetris</div>
</div>
<p>The pieces are as follows:</p>
<div id="in-a-row" class="section level4">
<h4>3-in-a-row</h4>
<p>Effectively 2 different ways to place it. Its just 3 consecutive
squares.</p>
</div>
<div id="l-shape" class="section level4">
<h4>L shape</h4>
<p>There are 4 different ways to place it. Its a 3-in-a-row with an
extra square attached to one of the ends. You can also use the third
dimension and flip it, leading to 8 different ways to place it.</p>
</div>
<div id="t-shape" class="section level4">
<h4>T shape</h4>
<p>There are 4 different ways to place it. Its a 3-in-a-row with an
extra square attached to the middle.</p>
</div>
<div id="square" class="section level4">
<h4>Square</h4>
<p>1 way to place it. Its a 2x2 square.</p>
</div>
<div id="smaller-l-shape" class="section level4">
<h4>Smaller L shape</h4>
<p>There are 4 different ways to place it. Its a 2-in-a-row with an
extra square attached to one of the ends.</p>
</div>
<div id="lines-offset-by-1" class="section level4">
<h4>2 lines offset by 1</h4>
<p>4 different ways.</p>
</div>
</div>
</div>
<div id="optimization" class="section level2">
<h2>Optimization</h2>
<ul>
<li><label><input type="checkbox"></input>Bitmasking</label></li>
<li>Pre-computing all possible positions of the pieces
<ul class="task-list">
<li><label><input type="checkbox" checked></input>Themselves</label></li>
<li><label><input type="checkbox"></input>On the (5x5) board</label></li>
</ul></li>
<li><label><input type="checkbox" checked></input>Skip recomputation of
<em>forbidden</em> pins by flipping the matrix around (sort
of)</label></li>
<li><label><input type="checkbox"></input>Store partial solutions (very
hard)</label></li>
</ul>
</div>
<div id="probabilities" class="section level2">
<h2>Probabilities</h2>
<div id="data" class="section level3">
<h3>Data</h3>
<div id="loading-data-and-libs" class="section level4">
<h4>Loading Data and libs</h4>
<div class="sourceCode" id="cb1"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb1-1"><a href="#cb1-1" tabindex="-1"></a><span class="fu">library</span>(jsonlite)</span>
<span id="cb1-2"><a href="#cb1-2" tabindex="-1"></a><span class="fu">library</span>(dplyr)</span>
<span id="cb1-3"><a href="#cb1-3" tabindex="-1"></a><span class="fu">library</span>(tidyr)</span>
<span id="cb1-4"><a href="#cb1-4" tabindex="-1"></a><span class="fu">library</span>(ggplot2)</span>
<span id="cb1-5"><a href="#cb1-5" tabindex="-1"></a><span class="fu">library</span>(plotly)</span></code></pre></div>
<div class="sourceCode" id="cb2"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb2-1"><a href="#cb2-1" tabindex="-1"></a>data <span class="ot">&lt;-</span> <span class="fu">fromJSON</span>(<span class="st">&quot;../src/data_extended.json&quot;</span>)</span></code></pre></div>
</div>
<div id="data-exploration" class="section level4">
<h4>Data Exploration</h4>
<div class="sourceCode" id="cb3"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb3-1"><a href="#cb3-1" tabindex="-1"></a><span class="fu">head</span>(data)</span></code></pre></div>
<pre><code>## pinA pinB pinC solution_count
## 1 0, 0 0, 4 4, 0 126
## 2 0, 0 0, 4 4, 4 126
## 3 0, 0 4, 0 0, 4 126
## 4 0, 0 4, 0 4, 4 126
## 5 0, 0 4, 4 0, 4 126
## 6 0, 0 4, 4 4, 0 126</code></pre>
<p>Each record contains three forbidden pins (<code>pinA</code>,
<code>pinB</code>, <code>pinC</code>) and a <code>solution_count</code>.
Important: - The first value in each tuple is the y-coordinate (row),
and the second value is the x-coordinate (column). -
<code>solution_count</code> indicates how many unique puzzle solutions
exist when pins are placed in the specified positions.</p>
</div>
</div>
<div id="data-preparation" class="section level3">
<h3>Data Preparation</h3>
<div id="flattening-pin-positions" class="section level4">
<h4>Flattening Pin Positions</h4>
<p>Since each pin is represented by a two-element vector
(<code>[y, x]</code>), we separate these into individual columns:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb5-1"><a href="#cb5-1" tabindex="-1"></a>data <span class="ot">&lt;-</span> data <span class="sc">%&gt;%</span></span>
<span id="cb5-2"><a href="#cb5-2" tabindex="-1"></a> <span class="fu">rowwise</span>() <span class="sc">%&gt;%</span></span>
<span id="cb5-3"><a href="#cb5-3" tabindex="-1"></a> <span class="fu">mutate</span>(</span>
<span id="cb5-4"><a href="#cb5-4" tabindex="-1"></a> <span class="at">pinA_y =</span> pinA[<span class="dv">1</span>],</span>
<span id="cb5-5"><a href="#cb5-5" tabindex="-1"></a> <span class="at">pinA_x =</span> pinA[<span class="dv">2</span>],</span>
<span id="cb5-6"><a href="#cb5-6" tabindex="-1"></a> <span class="at">pinB_y =</span> pinB[<span class="dv">1</span>],</span>
<span id="cb5-7"><a href="#cb5-7" tabindex="-1"></a> <span class="at">pinB_x =</span> pinB[<span class="dv">2</span>],</span>
<span id="cb5-8"><a href="#cb5-8" tabindex="-1"></a> <span class="at">pinC_y =</span> pinC[<span class="dv">1</span>],</span>
<span id="cb5-9"><a href="#cb5-9" tabindex="-1"></a> <span class="at">pinC_x =</span> pinC[<span class="dv">2</span>]</span>
<span id="cb5-10"><a href="#cb5-10" tabindex="-1"></a> ) <span class="sc">%&gt;%</span></span>
<span id="cb5-11"><a href="#cb5-11" tabindex="-1"></a> <span class="fu">ungroup</span>() <span class="sc">%&gt;%</span></span>
<span id="cb5-12"><a href="#cb5-12" tabindex="-1"></a> <span class="fu">select</span>(<span class="sc">-</span>pinA, <span class="sc">-</span>pinB, <span class="sc">-</span>pinC)</span></code></pre></div>
<p>We now have six columns representing the coordinates of each
forbidden pin: - <code>pinA_y</code>, <code>pinA_x</code> -
<code>pinB_y</code>, <code>pinB_x</code> - <code>pinC_y</code>,
<code>pinC_x</code></p>
</div>
</div>
<div id="game-context" class="section level3">
<h3>Game Context</h3>
<p>The IQ Mini 4489 puzzle is played on a <span class="math inline">\(5\times 5\)</span> grid, but the “tracks” for pin
placement are defined in the <a href="#table-container">table provided
above</a> where:</p>
<ul>
<li>Orange signifies <code>pinA</code>s range</li>
<li>Green signifies <code>pinB</code>s range</li>
<li>Purple signifies <code>pinC</code>s range</li>
</ul>
<p>We will compare two scenarios:</p>
<ol style="list-style-type: decimal">
<li>Scenario A: Pins (<code>pinA</code>, <code>pinB</code>,
<code>pinC</code>) can be placed anywhere on the <span class="math inline">\(5\times 5\)</span> grid.</li>
<li>Scenario B: Pins are restricted to their specific tracks as defined
in the table.</li>
</ol>
</div>
<div id="exploratory-data-analysis" class="section level3">
<h3>Exploratory Data Analysis</h3>
<div id="distribution-of-solution-counts" class="section level4">
<h4>Distribution of Solution Counts</h4>
<p>To visualize how often each solution count occurs, we use a
histogram:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb6-1"><a href="#cb6-1" tabindex="-1"></a><span class="fu">ggplot</span>(data, <span class="fu">aes</span>(<span class="at">x =</span> solution_count)) <span class="sc">+</span></span>
<span id="cb6-2"><a href="#cb6-2" tabindex="-1"></a> <span class="fu">geom_histogram</span>(<span class="at">binwidth =</span> <span class="dv">5</span>, <span class="at">fill =</span> <span class="st">&quot;blue&quot;</span>, <span class="at">color =</span> <span class="st">&quot;black&quot;</span>) <span class="sc">+</span></span>
<span id="cb6-3"><a href="#cb6-3" tabindex="-1"></a> <span class="fu">theme_minimal</span>() <span class="sc">+</span></span>
<span id="cb6-4"><a href="#cb6-4" tabindex="-1"></a> <span class="fu">labs</span>(</span>
<span id="cb6-5"><a href="#cb6-5" tabindex="-1"></a> <span class="at">title =</span> <span class="st">&quot;Distribution of Solution Counts&quot;</span>,</span>
<span id="cb6-6"><a href="#cb6-6" tabindex="-1"></a> <span class="at">x =</span> <span class="st">&quot;Solution Count&quot;</span>,</span>
<span id="cb6-7"><a href="#cb6-7" tabindex="-1"></a> <span class="at">y =</span> <span class="st">&quot;Frequency&quot;</span></span>
<span id="cb6-8"><a href="#cb6-8" tabindex="-1"></a> )</span></code></pre></div>
<p><img src="data:image/png;base64,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
</div>
<div id="forbidden-pin-influence-on-solution-counts" class="section level4">
<h4>Forbidden Pin Influence on Solution Counts</h4>
<p>We examine how the y-coordinates of each pin influence the
<code>solution_count</code>. Below is an example focusing on
<code>pinA_y</code>:</p>
<p><img src="data:image/png;base64,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
Seems like they are all pretty much the same.</p>
</div>
</div>
<div id="scenario-analysis" class="section level3">
<h3>Scenario Analysis</h3>
<div id="scenario-a-pins-can-be-placed-anywhere" class="section level4">
<h4>Scenario A: Pins Can Be Placed Anywhere</h4>
<p>Under this assumption, all grid squares are valid for pin
placement.</p>
<ul>
<li><p>Observations:</p>
<ul>
<li>Certain positions may drastically lower the number of solutions,
especially if they block puzzle pieces.</li>
<li>For example, placing a forbidden pin in the center might have a
different impact compared to placing it in a corner.</li>
</ul></li>
<li><p>Pairwise Heatmap (Example with the mean
<code>solution_count</code> of <code>pinA_x</code>
vs. <code>pinB_x</code>)</p>
<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABUAAAAPACAIAAAB7BESOAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAgAElEQVR4nOzdZ2AUVduH8Xtmd9NDGhB671V6bwKhCEpTwQIICOID9teGPvZeQLGjgApIEaRXkRZ670UQCJ2QhISQtrsz74dNAkk2PbI7T67fJyW7s/eZsjv/OWfmKLquCwAAAAAAcG+qqwsAAAAAAAC5I8ADAAAAAGAABHgAAAAAAAyAAA8AAAAAgAEQ4AEAAAAAMAACPAAAAAAABkCABwAAAADAAAjwAAAAAAAYAAEeAAAAAAADIMADAAAAAGAABHgAAAAAAAyAAA8AAAAAgAEQ4AEAAAAAMACzqwtwLev1Mwd27jp85kpUdGyi4uUXUKpSjbqNm99VNeBfWTH2U0smztxzUxdzvUEv3V//Dqz8lENzP5l/1CaKX7NHnulTzfTvf+K/ITnyyI7th89cvhp5Lc7q4R8YHFqtYYsWjaoEWlxdmfvQ43b+8uXyM3YRtVSHUU/cXTbXa3Ppe6Pi0eCBFwfWMejO8T9OO7/mm2lbYyv1HDe0ZYCS+o969Jap36w5b8/uTYpi8vQPCildqV6Lts1qhngqWV9i7G+GlMPzPpt/JEUXEVHMNfo++3ATH1fX9K/Qzq/5etqWaE3Mtfo9P6Sxl6vrKTzt4tpvf9p8vWKP/wxrFehkxwQAALnSi6eEk8s+faJ7zRImJ2cQiiW4bs9xX/55NqmoPzV55ajSqoiI18DZN4t64U7dmNXfS0RELTNmdfId+cSiZIvc+fOL/ZtX9HOymRRTYJ3e4yf/FWG8Zv0r7BGTO3uIiIi53oTd1jy8I31vVHwHzy/yfR1FwXbqh94hqho6eO4V7fZ/PvFxq7xdvFJMQfX7vTzrQJyWacmG/mZIWDW6/K0LVGrJhxfEurqkf0nK1hdqmEREPPtMj3Z1MUXDdnxiRz/FVGXEksjMOyUAAMiL4jiEPuHAlIea3tXnhe/W/B1n17P+XbdGH1351VNhDVuMmnki6c7Xl18pe6e9+Oyzzz77/NsLTmXbJ2c4icd+Gdm0ZuvhH/+x61y8k82k268fWz75qW6N24ydfTLFBQX+G/43N2UeFNuG50g7O3XcSyujvdq9/M6A0gXrrNTtMYcXfvhwmzZjFpz7n1mxN9fNWXxJS/9fLXrF3NXXXVgP8sNUa8z7Y2opZ37+z0vLY5z8/gIAgFwUuyH09pM/Dek5dskluy4iik/F1n0H9e3cvG6lUv4Wa3z05X8O71y/ZMGq/VeTdS3u4NRh3eLV8JlDKrn1AFPr8aWTJy1IElMl+72vDKju1rXmjR6z+b0B/d/YEKk5xsh6hjbq1rtrkxoVygRZkq9fOXtk9+Z1G/ZcSNBF12L2fD+0xw1l3c8PuvdWypP/vU2ZR8W24TnQoxa//uaqGKX8qFdG1MhujZiqDnzrlV5lMl2I1a0JMZf+3r120ZItEQm6iH7z8I/Dh9Soue7Fhv8Dd53c+HP2kqvabf+gxaycsypm4INBjMg2BO82Tz/fbcqYVb++9NHjd3/Y2tvV9QAAYDDFLMBr535+5sWll+y6iBrc7oWfZ7zVp0qm2wpHPPv2Z38veG3oqC+2xWj2c/PGj+/V8Y9h5Q06VMGn56dbdk3QRLGUqmmUU3frie8fHvDG+khNRDGFNBvxwdfvP9ayZKY91RZ1YN4H45/9YtMVm27957f/PNml9eKRlQ26lYAsUnZ9/trsS7pHs7HPhpXI9lVqqRb3jxhZy3m+f+vTc8snPPDw59uua6Lf2Prpuwsem/1gKUfKNeI3g0Ps6tnLojQRUYO739tw66IN8boeu2bO8ugHHg4hwRuCWvGh5x9+d823R76eMHXMmv9U5XsbAID8KF6/nPYTM79bHa2JiKni0GkLP8yS3h18ag74bNmMEVVNIqJFLX//y52GHaKtBlVr0qxZs2ZNG1XyN8bJre3ol6NeXHlVE1HM5ft+vXHTD49nSe8iYg5pNOTT1esm9SiliogWteKNd1fF3/lqgX+FHrngkx+OWsWn8+NDC/54QY+KvT+aP/m+kqqIiHZtxdw/Y9P+ZLxvBgc9esXslTGaiKil73tq4oiufoqI6HF/zl12jfHYhuHb+fGhdc16/IZJX4YnuroYAAAMplgFeD1yw18HrCIi5uqDn+hVMofzViW456tPt/VURMT2z/JlR2x3qMTiTr88e8IHm2/oIopHvefmzhpTL6fnLnvWfeLr1zr6KCKiXZz3/R9XOYPH/wT7iWmTFkdpSmCvEYMKN/pHLXf/k4McUxLoCbu27rcWTYGuol9bNnt1rC4ipnL9Hupaufegrv6KiOjxf81dyvFvHOZGw4a18FDsp6ZPWhDJdgMAID+K1RB6++ULlx0PclLLVS6fS7eWWrFNm8qmTSdsol2+cFnL5lXWqGNbNu46cf5yVII5oHSZyvXadGhe2T+/PWaJ+2Z9vuhvm6gl240Y283pCbv9xMJPZ+9P0hWfJg89d28Nk4hol9d9P2XjVc166KhNRESP3fHzu2+tV2+fGcp+bP7Hcw+l6DlPFpW/VqTNbKSGdho9unOoKokXdq5evGzd/ss2v1Jly5QuU7l+q47tGoR65nMtiIj9yE+TljmGSFQZOXFCW9/c3mCq+vDI7q9tWHRD1+PWL91w49H7nY42zl8DC7Y5HAq2cvKyKV0lbd1dirGWKFeteo3aDe+qG5r7dFb2uLN7t2w7eOZKVEy83cMvsHTlWg2btWxUwTfD6sxLwzOv0oQzmxb9sWLLyQSvwKCgoJIV6rfv2bVxaY8Mn31qy5/hh89diUm2BJWr3axTp+YVfXPsZs5btan069unf7Uywq74Nn342b7VTXIzYuuqJSu3nErw8AsIKlWmXJX67bq0quJX8OBt3ffrz7uTdSWw26Aehb6x26NeozoWuZAsol27fNUmYhHJ/puhaI5uPfHy4Z3b9hyJuBoTb/cKKFWhVuOWrZtU9i/sBWP96pLZa2/oImKqNGBIB2/Fo9egrv6L/ojT9Zvr5iy+PPzxss5WV0EalT6BmxrQcuhTvbK5PUeP3fHL5BVn7KmT2dU+PnPi4pM2ETW08+jRnUIzvcl2dP4n8w6l6CLOp4XTY7ZO+3r1ObuIWrrjqDFdnM4FqSde2LV27c7jF2JSLP6lKtVr2bF9ozJ5mF8uXweydnbFl7/siNVMFcOefKxNsCIiiWe3rPhr59HDh73u+/r5Dpluu8j/t4SpWv+BzSds2xK7atq8c0OerFSs+hIAACgcVz8G/06y7X+zseOKhaniE2tyncctIWLPxvXr16/fEH70Wpb5brQbx+b/t1+9QHOm80XFs0zLYZ/9eTbR2RKzmUZOuza1l6eIiLn2S9uzmQAsafGjgYqIqCGPLU+d9cm65zXnU8mroY+vSn1N0vzBvopkO1lUgVqRNrORudEb+6w3j818vHGJzCdfimeZNk9M3Rebz2mCrLsn1HO0yNz4zf22PL3HfnHxa48MHjx48OCHnplxIvN7CtLAAm4Oh4KtnLxsytzWQ9FPIxd/YuEb/esHWzKuO8UcXL/fq7MPZbdxtRtH57/54F0lLVmSlKL6Vu70xLfbIu35avhtq3Rv7KFpwxpmjoGKZ7kur668YNV1XU86s/y/var4KLd/uGIp2WLMr0edHvD5qjZtVZ+e2N5DRNTSo1YmRm2bdH9Nn8y7l+pTsfNTP++LKdg8Wckbn65qElFKDJgV7XQJt6aRs7T88HguB4p24duuqcnUq9/MuNR/ze6bobBHtxZ3aNaLfeoGZTniVP9q3Z+dcTDLfHb5Yb/wfZhjXZtr/d/WFF3Xde3azAEBioiI4t3t23NZNlbBG3Vj4aOOew8szd8/ks061q7N7B+giIji0eaTEzbdujt1f1b8+s3Isu2s+95olLa3m6o9G56SeXHxix4NUUVE1JJDF8XfXrl49pkerdmubvrsgXoBGWfVVDxCWz0+ZW8OX7YFOJBT1o2raBIRS5tP/rbrWvSmD3pX8Xas5qBhS5IKt/BUqXux4tH64yxf3AAA
<p>We can see that the solution count is generally higher when the pins
are further apart and that my observations were correct.</p></li>
</ul>
</div>
<div id="scenario-b-pins-must-follow-their-tracks" class="section level4">
<h4>Scenario B: Pins Must Follow Their Tracks</h4>
<p>Here, each pin must stay on its designated track. <strong>Note that
were using aggregated data for this analysis.</strong> (i.e., were
taking the mean of <code>solution_count</code> for each unique pin
configuration).</p>
<div id="defining-valid-positions" class="section level5">
<h5>Defining Valid Positions</h5>
<p>First, we define the allowed positions for each pin based on the game
context:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb7-1"><a href="#cb7-1" tabindex="-1"></a>allowed_pinA <span class="ot">&lt;-</span> <span class="fu">tibble</span>(</span>
<span id="cb7-2"><a href="#cb7-2" tabindex="-1"></a> <span class="at">pinA_y =</span> <span class="fu">c</span>(<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>), <span class="co"># Orange track</span></span>
<span id="cb7-3"><a href="#cb7-3" tabindex="-1"></a> <span class="at">pinA_x =</span> <span class="fu">c</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">1</span>, <span class="dv">1</span>)</span>
<span id="cb7-4"><a href="#cb7-4" tabindex="-1"></a>)</span>
<span id="cb7-5"><a href="#cb7-5" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" tabindex="-1"></a>allowed_pinB <span class="ot">&lt;-</span> <span class="fu">tibble</span>(</span>
<span id="cb7-7"><a href="#cb7-7" tabindex="-1"></a> <span class="at">pinB_y =</span> <span class="fu">c</span>(<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">4</span>), <span class="co"># Green track</span></span>
<span id="cb7-8"><a href="#cb7-8" tabindex="-1"></a> <span class="at">pinB_x =</span> <span class="fu">c</span>(<span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">4</span>, <span class="dv">4</span>, <span class="dv">4</span>, <span class="dv">3</span>, <span class="dv">4</span>)</span>
<span id="cb7-9"><a href="#cb7-9" tabindex="-1"></a>)</span>
<span id="cb7-10"><a href="#cb7-10" tabindex="-1"></a></span>
<span id="cb7-11"><a href="#cb7-11" tabindex="-1"></a>allowed_pinC <span class="ot">&lt;-</span> <span class="fu">tibble</span>(</span>
<span id="cb7-12"><a href="#cb7-12" tabindex="-1"></a> <span class="at">pinC_y =</span> <span class="fu">c</span>(<span class="dv">2</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">4</span>, <span class="dv">4</span>), <span class="co"># Purple track</span></span>
<span id="cb7-13"><a href="#cb7-13" tabindex="-1"></a> <span class="at">pinC_x =</span> <span class="fu">c</span>(<span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">0</span>, <span class="dv">2</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>)</span>
<span id="cb7-14"><a href="#cb7-14" tabindex="-1"></a>)</span></code></pre></div>
</div>
<div id="filtering-data-for-scenario-b" class="section level5">
<h5>Filtering Data for Scenario B</h5>
<p>Next, we filter the dataset to include only the configurations where
each pin is placed on its respective track:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb8-1"><a href="#cb8-1" tabindex="-1"></a>valid_scenarioB <span class="ot">&lt;-</span> data <span class="sc">%&gt;%</span></span>
<span id="cb8-2"><a href="#cb8-2" tabindex="-1"></a> <span class="fu">semi_join</span>(allowed_pinA, <span class="at">by =</span> <span class="fu">c</span>(<span class="st">&quot;pinA_y&quot;</span>, <span class="st">&quot;pinA_x&quot;</span>)) <span class="sc">%&gt;%</span></span>
<span id="cb8-3"><a href="#cb8-3" tabindex="-1"></a> <span class="fu">semi_join</span>(allowed_pinB, <span class="at">by =</span> <span class="fu">c</span>(<span class="st">&quot;pinB_y&quot;</span>, <span class="st">&quot;pinB_x&quot;</span>)) <span class="sc">%&gt;%</span></span>
<span id="cb8-4"><a href="#cb8-4" tabindex="-1"></a> <span class="fu">semi_join</span>(allowed_pinC, <span class="at">by =</span> <span class="fu">c</span>(<span class="st">&quot;pinC_y&quot;</span>, <span class="st">&quot;pinC_x&quot;</span>))</span></code></pre></div>
</div>
<div id="analyzing-scenario-b" class="section level5">
<h5>Analyzing Scenario B</h5>
<p>Once filtered, we can perform similar analyses as in Scenario A:</p>
<ul>
<li><p>Distribution of Solution Counts:</p>
<p><img src="data:image/png;base64,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
<li><p>Pairwise Heatmap (Example with <code>pinA_x</code>
vs. <code>pinB_x</code>):</p>
<p><img src="data:image/png;base64,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
<p><sub> Wow, thats an interesting one! </sub></p>
<p>The observation here is that it is not similar to the previous one
whatsoever. Once <code>pinA_x</code> is placed at 3, the solution count
is generally lower, regardless of the <code>pinB_x</code> position. A
hypothesis as to why this is the case is that the <code>pinA</code>
track is close to the edge of the board, which might limit the movement
of puzzle pieces.</p>
<p>That hypothesis crumbles, however, as once <code>pinB_x</code> is
placed at 3.5, specifically when <code>pinA_x</code> <span class="math inline">\(&lt; 3\)</span>, the solution count is generally
higher. This suggests that the <code>pinB</code> track might have a more
significant impact on the puzzles solvability.</p>
<p>Considering this interesting development, lets look at the other
pairwise heatmaps to see if there are any similar patterns.</p>
<p><img src="data:image/png;base64,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
<p><img src="data:image/png;base64,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
<p>Observing the above heatmaps, more interesting patterns emerge. Seems
like its definitive that if <code>pinA_x</code> is placed at 3, the
solution count is generally lower, regardless of the other pins
positions. This is a stark contrast to the scenario where pins can be
placed anywhere, where the solution count was generally higher when the
pins were further apart.</p>
<p>The highest solution counts are observed when <code>pinA_x</code> is
placed at 0 or 1, and <code>pinB_x</code> is placed at 3 or 4. This
suggests that the puzzle is more solvable when the <code>pinA</code> and
<code>pinB</code> tracks are further apart on the x axis.</p>
<p>Its also curious that when <code>pinA_x</code> is placed at 3 and
<code>pinC_x</code> <span class="math inline">\(\in [1,2]\)</span> we
get the lowest solution counts of <span class="math inline">\(10\)</span>.</p>
<p>Lets wrap this up with a final comparison of all three pins
positions:</p>
<div class="plotly html-widget html-fill-item" id="htmlwidget-afaa605e3584cee383bf" style="width:672px;height:480px;"></div>
<script type="application/json" data-for="htmlwidget-afaa605e3584cee383bf">{"x":{"visdat":{"55a4a15741dad":["function () ","plotlyVisDat"]},"cur_data":"55a4a15741dad","attrs":{"55a4a15741dad":{"line":{"color":{},"colorscale":"Viridis"},"dimensions":[{"label":"pinA_x","values":{}},{"label":"pinB_x","values":{}},{"label":"pinC_x","values":{}},{"label":"Solution Count","values":{}}],"alpha_stroke":1,"sizes":[10,100],"spans":[1,20],"type":"parcoords"}},"layout":{"margin":{"b":40,"l":60,"r":10},"hovermode":"closest","showlegend":false},"source":"A","config":{"modeBarButtonsToAdd":["hoverclosest","hovercompare"],"showSendToCloud":false},"data":[{"line":{"color":[48.200000000000003,31.951219512195124,25.559999999999999,26.359999999999999,38.719999999999999,31.951219512195124,16.918918918918919,15.891891891891891,12.710280373831775,19.739130434782609,25.559999999999999,15.891891891891891,12.897959183673469,16.032,23.399999999999999,26.359999999999999,12.710280373831775,16.032,16.333333333333332,19.739130434782609,38.719999999999999,19.739130434782609,23.399999999999999,19.739130434782609,38.719999999999999,31.951219512195124,16.918918918918919,15.891891891891891,12.710280373831775,19.739130434782609,16.918918918918919,17.142857142857142,11.125,17.696969696969695,16.333333333333332,15.891891891891891,11.125,11.041666666666666,8.8288288288288292,16.032,12.710280373831775,17.696969696969695,8.8288288288288292,17.696969696969695,12.710280373831775,19.739130434782609,16.333333333333332,16.032,12.710280373831775,26.359999999999999,25.559999999999999,15.891891891891891,12.897959183673469,16.032,23.399999999999999,15.891891891891891,11.125,11.041666666666666,8.8288288288288292,16.032,12.897959183673469,11.041666666666666,7.5555555555555554,11.041666666666666,12.897959183673469,16.032,8.8288288288288292,11.041666666666666,11.125,15.891891891891891,23.399999999999999,16.032,12.897959183673469,15.891891891891891,25.559999999999999,26.359999999999999,12.710280373831775,16.032,16.333333333333332,19.739130434782609,12.710280373831775,17.696969696969695,8.8288288288288292,17.696969696969695,12.710280373831775,16.032,8.8288288288288292,11.041666666666666,11.125,15.891891891891891,16.333333333333332,17.696969696969695,11.125,17.142857142857142,16.918918918918919,19.739130434782609,12.710280373831775,15.891891891891891,16.918918918918919,31.951219512195124,38.719999999999999,19.739130434782609,23.399999999999999,19.739130434782609,38.719999999999999,19.739130434782609,16.333333333333332,16.032,12.710280373831775,26.359999999999999,23.399999999999999,16.032,12.897959183673469,15.891891891891891,25.559999999999999,19.739130434782609,12.710280373831775,15.891891891891891,16.918918918918919,31.951219512195124,38.719999999999999,26.359999999999999,25.559999999999999,31.951219512195124,48.200000000000003],"colorscale":"Viridis"},"dimensions":[{"label":"pinA_x","values":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},{"label":"pinB_x","values":[0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4]},{"label":"pinC_x","values":[0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4]},{"label":"Solution Count","values":[48.200000000000003,31.951219512195124,25.559999999999999,26.359999999999999,38.719999999999999,31.951219512195124,16.918918918918919,15.891891891891891,12.710280373831775,19.739130434782609,25.559999999999999,15.891891891891891,12.897959183673469,16.032,23.399999999999999,26.359999999999999,12.710280373831775,16.032,16.333333333333332,19.739130434782609,
<p><img src="data:image/png;base64,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
</ul>
</div>
</div>
</div>
<div id="d-visualization" class="section level3">
<h3>3D Visualization</h3>
<p>We can use a 3D scatter plot to visualize how pin positions affect
<code>solution_count</code> for both scenarios. These are a bit
confusing, but theyre fun to look at.</p>
<ul>
<li><p>Scenario A (Pins Anywhere):</p>
<div class="plotly html-widget html-fill-item" id="htmlwidget-b6e871af04c5e2ac7721" style="width:672px;height:480px;"></div>
<script type="application/json" data-for="htmlwidget-b6e871af04c5e2ac7721">{"x":{"visdat":{"55a4a51412a90":["function () ","plotlyVisDat"]},"cur_data":"55a4a51412a90","attrs":{"55a4a51412a90":{"x":{},"y":{},"z":{},"color":{},"alpha_stroke":1,"sizes":[10,100],"spans":[1,20],"type":"scatter3d","mode":"markers","inherit":true}},"layout":{"margin":{"b":40,"l":60,"t":25,"r":10},"title":"Solution Count by Pin A X & Pin B X (Pins Anywhere)","scene":{"xaxis":{"title":"Pin A X"},"yaxis":{"title":"Pin B X"},"zaxis":{"title":"Solution Count"}},"hovermode":"closest","showlegend":false,"legend":{"yanchor":"top","y":0.5}},"source":"A","config":{"modeBarButtonsToAdd":["hoverclosest","hovercompare"],"showSendToCloud":false},"data":[{"x":[0,0,0,0,0,0,0,0,1,1,3,3,0,0,0,0,0,0,0,0,1,1,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2,2,2,2,2,2,2,2,3,3,0,0,0,0,0,0,0,0,1,1,3,3,0,0,0,0,2,2,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,1,1,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,3,3,3,3,3,3,0,0,0,0,1,1,1,1,3,3,3,3,0,0,2,0,0,0,0,2,2,0,0,0,0,1,1,1,1,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,3,2,2,2,2,0,0,0,0,0,0,0,0,0,0,1,1,2,2,2,2,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,1,1,1,1,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,1,1,1,1,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,1,1,1,1,1,1,1,1,2,2,2,2,1,1,1,1,1,1,2,2,2,2,3,3,3,3,3,3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,1,1,2,2,2,2,2,2,2,2,0,0,0,0,1,1,3,3,2,2,2,2,0,0,0,0,0,0,0,0,1,1,2,2,2,2,3,3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,0,0,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
<li><p>Scenario B (Pins on Tracks):</p>
<div class="plotly html-widget html-fill-item" id="htmlwidget-c31ed6c73d16eeee5dea" style="width:672px;height:480px;"></div>
<script type="application/json" data-for="htmlwidget-c31ed6c73d16eeee5dea">{"x":{"visdat":{"55a4a79cdd8c3":["function () ","plotlyVisDat"]},"cur_data":"55a4a79cdd8c3","attrs":{"55a4a79cdd8c3":{"x":{},"y":{},"z":{},"color":{},"alpha_stroke":1,"sizes":[10,100],"spans":[1,20],"type":"scatter3d","mode":"markers","inherit":true}},"layout":{"margin":{"b":40,"l":60,"t":25,"r":10},"title":"Solution Count by Pin A X & Pin B X (Pins on Tracks)","scene":{"xaxis":{"title":"Pin A X"},"yaxis":{"title":"Pin B X"},"zaxis":{"title":"Solution Count"}},"hovermode":"closest","showlegend":false,"legend":{"yanchor":"top","y":0.5}},"source":"A","config":{"modeBarButtonsToAdd":["hoverclosest","hovercompare"],"showSendToCloud":false},"data":[{"x":[0,0,1,0,0,0,0,0,0,0,0,2,0,0,1,1,1,0,0,0,1,1,2,1,1,2,1,1,2,0,0,0,0,1,1,2,0,1,1,0,1,2,0,0,0,1,1,2,0,0,2,0,1,2,2,2,1,1,1,1,2,0,1,1,1,1,2,2,2,2,2,0,1,2,1,1,0,1,1,2,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,0,0,0,1,1,1,1,1,1,1,1,2,2,2,0,0,1,1,2,2,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,1,2,2,0,0,0,1,1,2,2,2,2,0,0,1,2,2,0,0,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,2,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,2,1,1,1,1,1,1,0,1,1,1,2,1,3,0,0,1,3,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,0,3,3,1,1,3,1,1,3,1,1,1,0,0,3,3,1,1,1,0,0,0,0,0,0,0,3,3,3,3,1,1,1,1,0,0,0,0,0,3,1,0,3,3,3,3,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,3,1,1,0,0,3,1,1,1,0,1,1,1,1,1,1,0,0,0,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,3,3,3,3,3,3,3,1,1,1,1,1,0,3,1,1,0,0,3,3,3,3,1,1,1,0,3,3,1,1,3,3,3,3,1,1,1,1,0,3,3,3,1,1,1,1,1,1,3,1,3,3,1,1,1],"y":[4,4,4,4,4,4,3,4,3,4,4,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,4,3,4,4,4,4,4,4,4,4,3,4,4,4,4,4,3,3,4,4,3,3,3,4,4,4,4,4,4,3,3,4,4,4,4,4,3,3,4,3,4,3,4,4,3,4,4,4,4,3,3,4,4,3,4,4,4,4,3,3,3,4,4,4,4,3,4,4,3,3,4,3,4,4,4,4,4,3,4,4,4,4,3,4,4,4,4,4,3,4,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,3,4,3,3,4,3,3,4,3,3,3,4,4,4,4,3,3,4,4,4,4,3,4,3,3,4,4,3,4,3,4,4,3,4,3,4,4,4,3,3,4,4,3,4,4,4,4,4,4,3,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,4,4,3,4,4,4,4,3,4,4,3,4,4,3,3,4,4,4,3,3,4,4,3,3,4,3,4,4,4,3,4,3,3,4,4,3,3,4,4,3,3,4,3,3,3,3,4,4,4,4,4,4,3,3,4,4,4,3,3,4,4,4,3,4,4,4,4,4,3,4,4,4,4,4,4,4,4,4,3,3,4,4,3,4,4,4,3,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,3,4,4,4,4,4,3,3,4,4,4,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,4,4,4,4,4,3,3,4,4,4,4,4,4,3,4,3,4,4,4,4,3,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,4,4,4,4,4,3,4,4,3,4,4],"z":[126,126,59,58,58,58,55,55,55,52,50,50,41,41,41,41,41,40,40,40,40,39,38,37,37,36,34,34,34,32,31,31,31,31,31,31,29,29,29,28,28,28,26,26,26,26,26,26,25,25,25,24,24,24,23,23,22,22,22,22,22,21,21,21,21,21,21,21,21,21,21,20,20,20,19,19,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,13,13,12,12,12,12,12,12,12,12,12,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,8,8,7,7,7,6,6,6,6,6,6,6,6,5,5,5,5,5,5,4,3,3,3,3,2,59,55,41,41,38,36,34,34,31,31,29,29,29,28,28,28,28,26,26,26,25,25,25,24,24,24,24,24,23,22,22,22,22,22,22,22,22,22,21,21,21,21,21,21,20,20,20,19,19,19,19,18,18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,13,13,13,12,12,12,12,12,12,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,6,6,6,6,6,6,6,6,6,5,5,5,5,5,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,2,2,1,1,1,1,1],"type":"scatter3d","mode":"markers","marker":{"colorbar":{"title":"solution_count","ticklen":2},"cmin":1,"cmax":126,"colorscale":[["0","rgba(68,1,84,1)"],["0.0416666666666667","rgba(70,19,97,1)"],["0.0833333333333333","rgba(72,32,111,1)"],["0.125","rgba(71,45,122,1)"],["0.166666666666667","rgba(68,58,128,1)"],["0.208333333333333","rgba(64,70,135,1)"],["0.25","rgba(60,82,138,1)"],["0.291666666666667","rgba(56,93,140,1)"],["0.333333333333333","rgba(49,104,142,1)"],["0.375","rgba(46,114,142,1)"],["0.416666666666667","rgba(42,123,142,1)"],["0.458333333333333","rgba(38,133,141,1)"],["0.5","rgba(37,144,140,1)"],["0.541666666666667","rgba(33,154,138,1)"],["0.583333333333333","rgba(39,164,133,1)"]
</ul>
</div>
<div id="probability-analysis" class="section level3">
<h3>Probability Analysis</h3>
<p>We categorize <code>solution_count</code> into three levels:</p>
<ul>
<li>High (upper 25%)</li>
<li>Medium (50%, average)</li>
<li>Low (lower 25%)</li>
</ul>
<p>based on the 25th and 75th percentiles, and then compute
probabilities for both Scenario A and Scenario B.</p>
<div id="defining-categories" class="section level4">
<h4>Defining Categories</h4>
<div class="sourceCode" id="cb9"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb9-1"><a href="#cb9-1" tabindex="-1"></a>high_threshold_A <span class="ot">&lt;-</span> <span class="fu">quantile</span>(data<span class="sc">$</span>solution_count, <span class="fl">0.75</span>)</span>
<span id="cb9-2"><a href="#cb9-2" tabindex="-1"></a>low_threshold_A <span class="ot">&lt;-</span> <span class="fu">quantile</span>(data<span class="sc">$</span>solution_count, <span class="fl">0.25</span>)</span>
<span id="cb9-3"><a href="#cb9-3" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" tabindex="-1"></a>data <span class="ot">&lt;-</span> data <span class="sc">%&gt;%</span></span>
<span id="cb9-5"><a href="#cb9-5" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="at">solution_category_A =</span> <span class="fu">case_when</span>(</span>
<span id="cb9-6"><a href="#cb9-6" tabindex="-1"></a> solution_count <span class="sc">&gt;=</span> high_threshold_A <span class="sc">~</span> <span class="st">&quot;High&quot;</span>,</span>
<span id="cb9-7"><a href="#cb9-7" tabindex="-1"></a> solution_count <span class="sc">&lt;=</span> low_threshold_A <span class="sc">~</span> <span class="st">&quot;Low&quot;</span>,</span>
<span id="cb9-8"><a href="#cb9-8" tabindex="-1"></a> <span class="cn">TRUE</span> <span class="sc">~</span> <span class="st">&quot;Medium&quot;</span></span>
<span id="cb9-9"><a href="#cb9-9" tabindex="-1"></a> ))</span>
<span id="cb9-10"><a href="#cb9-10" tabindex="-1"></a></span>
<span id="cb9-11"><a href="#cb9-11" tabindex="-1"></a>high_threshold_B <span class="ot">&lt;-</span> <span class="fu">quantile</span>(valid_scenarioB<span class="sc">$</span>solution_count, <span class="fl">0.75</span>)</span>
<span id="cb9-12"><a href="#cb9-12" tabindex="-1"></a>low_threshold_B <span class="ot">&lt;-</span> <span class="fu">quantile</span>(valid_scenarioB<span class="sc">$</span>solution_count, <span class="fl">0.25</span>)</span>
<span id="cb9-13"><a href="#cb9-13" tabindex="-1"></a></span>
<span id="cb9-14"><a href="#cb9-14" tabindex="-1"></a>valid_scenarioB <span class="ot">&lt;-</span> valid_scenarioB <span class="sc">%&gt;%</span></span>
<span id="cb9-15"><a href="#cb9-15" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="at">solution_category_B =</span> <span class="fu">case_when</span>(</span>
<span id="cb9-16"><a href="#cb9-16" tabindex="-1"></a> solution_count <span class="sc">&gt;=</span> high_threshold_B <span class="sc">~</span> <span class="st">&quot;High&quot;</span>,</span>
<span id="cb9-17"><a href="#cb9-17" tabindex="-1"></a> solution_count <span class="sc">&lt;=</span> low_threshold_B <span class="sc">~</span> <span class="st">&quot;Low&quot;</span>,</span>
<span id="cb9-18"><a href="#cb9-18" tabindex="-1"></a> <span class="cn">TRUE</span> <span class="sc">~</span> <span class="st">&quot;Medium&quot;</span></span>
<span id="cb9-19"><a href="#cb9-19" tabindex="-1"></a> ))</span></code></pre></div>
</div>
<div id="calculating-probabilities" class="section level4">
<h4>Calculating Probabilities</h4>
<div id="scenario-a-probability-analysis" class="section level5">
<h5>Scenario A Probability Analysis</h5>
<div class="sourceCode" id="cb10"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb10-1"><a href="#cb10-1" tabindex="-1"></a>probabilities_A <span class="ot">&lt;-</span> data <span class="sc">%&gt;%</span></span>
<span id="cb10-2"><a href="#cb10-2" tabindex="-1"></a> <span class="fu">group_by</span>(solution_category_A) <span class="sc">%&gt;%</span></span>
<span id="cb10-3"><a href="#cb10-3" tabindex="-1"></a> <span class="fu">summarise</span>(<span class="at">count =</span> <span class="fu">n</span>(), <span class="at">.groups =</span> <span class="st">&#39;drop&#39;</span>) <span class="sc">%&gt;%</span></span>
<span id="cb10-4"><a href="#cb10-4" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="at">probability =</span> count <span class="sc">/</span> <span class="fu">sum</span>(count))</span>
<span id="cb10-5"><a href="#cb10-5" tabindex="-1"></a>probabilities_A</span></code></pre></div>
<pre><code>## # A tibble: 3 × 3
## solution_category_A count probability
## &lt;chr&gt; &lt;int&gt; &lt;dbl&gt;
## 1 High 3156 0.251
## 2 Low 3456 0.275
## 3 Medium 5976 0.475</code></pre>
</div>
<div id="scenario-b-probability-analysis" class="section level5">
<h5>Scenario B Probability Analysis</h5>
<div class="sourceCode" id="cb12"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb12-1"><a href="#cb12-1" tabindex="-1"></a>probabilities_B <span class="ot">&lt;-</span> valid_scenarioB <span class="sc">%&gt;%</span></span>
<span id="cb12-2"><a href="#cb12-2" tabindex="-1"></a> <span class="fu">group_by</span>(solution_category_B) <span class="sc">%&gt;%</span></span>
<span id="cb12-3"><a href="#cb12-3" tabindex="-1"></a> <span class="fu">summarise</span>(<span class="at">count =</span> <span class="fu">n</span>(), <span class="at">.groups =</span> <span class="st">&#39;drop&#39;</span>) <span class="sc">%&gt;%</span></span>
<span id="cb12-4"><a href="#cb12-4" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="at">probability =</span> count <span class="sc">/</span> <span class="fu">sum</span>(count))</span>
<span id="cb12-5"><a href="#cb12-5" tabindex="-1"></a>probabilities_B</span></code></pre></div>
<pre><code>## # A tibble: 3 × 3
## solution_category_B count probability
## &lt;chr&gt; &lt;int&gt; &lt;dbl&gt;
## 1 High 99 0.253
## 2 Low 126 0.321
## 3 Medium 167 0.426</code></pre>
</div>
</div>
<div id="visualizing-probabilities" class="section level4">
<h4>Visualizing Probabilities</h4>
<p><strong>Note that HIGH would mean “easy” in this case</strong>.
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABUAAAAPACAIAAAB7BESOAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAgAElEQVR4nOzdZ2AUVduH8Xtmd1MJaQRCDb33JlVQiqiogChNbKCor2Avj+VReey9K/aCShEEka703qT33kJLDynb5v2woSTZTTbJwuaE6/cJkt2d+8yZmcx/z8wczTAMAQAAAAAApZvu7wIAAAAAAEDhCPAAAAAAACiAAA8AAAAAgAII8AAAAAAAKIAADwAAAACAAgjwAAAAAAAogAAPAAAAAIACCPAAAAAAACiAAA8AAAAAgAII8AAAAAAAKIAADwAAAACAAgjwAAAAAAAogAAPAAAAAIACzP4uQB1G4orvPp9/1OHp95pmCgyLjK5Yo3G7Tm3qRQdql7M4EREjefUPn8457BBTlR4PjOxS4XIVULLlWrdOemfKDrto5drc8Wjf2qZzP3fsm/HBLxvOGmJuPPCZ25qYC3u9ohzJuxbPWbTxYII1MKb1TcN71w0qxofYkg9uXrtu28GTCYkpmVpQufCYGnUbtWjbslb4Jdm/PXXNpVM2Oj379PY1q7cdPHHq9JlUW0BYRFSl2s3atWteM8Li78rKhLKxkQAAABTGgJfsu9++yrszbc0U2aTfs79uTnVe1gIdBz7oEiAiYmn7+na7KstN+7V/kIiIHjtqXvZFP8+eM7KiLiISdOuEs168XkH2w3883CbSdO4Lj8AeXxwv4haTsXfmuw/0qlfe5OZLE80S1ajPwx//fSjL13V76ppLR+1Ot59e++PT/dtWL+emmzRTRMMbRn+y4LB6zSpt1N5IAAAAvMQl9JeA4UjaNu3NYR07jpp6xOOAPXzN+u/3Tz/22GOPPTF26j4FVrvz4Ncj7/psfZLDKN77MzZ/PbR1y75Pfjl/T6q7zzBsiTvmfDqmd7N2I3/ZnVWyWi8HxbrPS5k7fxrRul6Hu9/+Y92RdDfdZDiSd876ZEzPFh0fnLDX6ssll831CQAAcKXjEvpiMNW69ZX/XB+b58sPw5aRFL9n/T/TZ6w4nGGIGGe3fXP3kLr1Fj7djEtkLwfbrr8++XBqlphqOG7+z4A6pfwSWufh6b8uSjVEtMDGd3325bPX1Y8KDYv29vYDx95vh/R5cEa8wxARLaR6h5sG3tS9baMaMWEWW3riif3b1i6aMXXuplPZhjN1y3d39UzXl/0ypEapXiVqdZ83jKTlrw3o/9Li005DREQLrNS85w09WtWtFhtpyU4+eWj7+uULF284lmGI4UzaMO7O69K0hT8O8lUvlb31CQAAAAJ8segx7W67d0R996fEr7x7ZNbztw97f1WyU4y0le++OvWeCYNiLvsN8coI6fPuinXPO0WzxNTz5ouOor6+tHIcPeR6nkLA1WPeuLdrbFG2EOeRHx99+q94hyGiR3V+8sfxr/Stmefe+XsfG/venqkv3Dnyo1VJTseRyaNHX3/1H3dVVfSKGxU73bZ73LABLy067RTRTNFt7n3js9fvaV8hzwHXnrB58hujH/to6Um7Ydv/2/89dE2HP0fEKdpLfqbiRgIAAFBkBHifC6h+w1tTPtnX4q4/zjjFeWb2pL9TBg2J8HdVpZYeWbtVm0v4+lLLYXdd2KyFhYcV7fsdx+5fvpyX6BQRU/U7v5/2Zl/3zw0MqTfgvZlBaW1v/uaAw5kw6/WP1w5566qAEtftD+p1un3HxyOfnnPKKaKZq9706byJoxq7ezyhObr5kHfntazVr9uYOaedzoTZL706d9DX15e77PWWAeptJAAAAMXAWM+loFe57aGBlXURESNj3cpNNn8XhDLEOL14wWabiIi5zuAHri/oqf9aVJ/nHukUqImIff+smdvtl6nEK51xYsLzbyxPM0S0gMaPT/rVfXo/J7DRA5+9cHWIJiLO45PH/XGqmE9FAAAAQNnHCPylEdC4eUOLHMsWcZ45ccouYhERcR6a/fFPa1Kcpuq9H7qnY5QmIpmHVsxesHbHtm1Bt3z2RNd8V37aEnauWLJu99ETCRnm8IqxcY07dm0bF+b1/axGxpG1C5ZuPnj8TGZAdOW4hld161gvwos+d6Qe+nfFqi0HTyYkpTsCykVUjKvfrE375tVCvfzCpwjLdeyc8vakrVbD28mf8r/eeWLhuK+XnHLatu6wi4gYKWt+fPWVRXrOfFI14+d/9v2KRKfo4e3vHHO9h+uTjZQ1P30y+6BDNHPdmx4b1irEu4Ze4HVPZW367b1pu+3OQ2tSDBER+44pb7yyyyJirt33keFtCh98dZw4dsI1eK9XiatayArTq3fsGGdautsuzhPHTjhLWnyBMjf++v70PXbRK3S+98Gebi/Xd+ye9u6ETVmGFtJq6OM31zVJod1X2yTebiRFa4XzqGu70Ct1u//+7pV0yTy2dt6fMxduOmEvF1M5tmJsXJOrru7ctFJgEdeCiDi2f/vhTNclEjVHfPB8p9DC3mCqNWxErxcWT08zjNRFfy1OG35beXcf69Ve6c36vNi5tRafZCtfpXadug2atWxUyavJDG1nti5esHbX4VNZIZVqNurY4+oGESYRI3nVD5/OPezQwtoNf+SGWp5WfxE7y4sjp5dHkuK018g8sW3tqg3bD59KSncEhcdUq9+ifYdWcWF8/w0AAPzA34/BV8eFaeQs7d/cVch0ac5jX/TIOfMP6vdLas5PrQsfrm4SEUvHd/Y4DGfi0jduqBmsiYhokXfNyDXdlzNt55T/9mscYc4zvqoFxra/672/D2XmX2bu6dzs8QvfGNAwPPfMVVpgpfZ3f7wk3uqx7rQdU14e1LKCJd+wrqaHxnV74ItVpx2+XW7WlMGhmng/jVz+19s2vOB+LnK90n1zsw0jbdrwCvr5+jy0+8wv/cM1EdECOr6zu0hz4RW1pxJ/6Os+E3o7jZx908stXO01VX9gfqHzuGUc3rBk0aJFixYv23Em38cXYzPz2DXOM99dHygiYm7wzGqb+2Ky/hweoYmIHn3PrJzeLqz7DMPzRlKSVlhXPlnXJCLm5i9ttJ3d+ct9LcrnzWNaYGzHB77bmFLEyf1s659v7GqRucXLm7zbmBzH/3zhjsGDBw8ePPTR8Xk3wCLtld6sT5f03dNe6t8kKs+nauaoJv2em7C1oFY7Etd9dV+H2MCL36mF1Oj51O+7z9r3vd85QET0qg/+4242t+J1lhdHzkI2kuK115m69den+zaKzFetHla712Pjt1zmqUIBAAAMArzXihTgsxY8VM01BKTHjJh97nTyotPQ3UkrX+kYcT4x5A7w9qN/PtyynOdLozU9pvvYZQl5zh0vCtJj5/w8JC7/6X7Ouy3V+32xxU3wcxyf+Wjb8AJHlbSQJmPm5smBJVtuyQO8ffOb3arFxsZWighyndKbQqJiY2NjY6s0e3KR1TCM1KnDol0J/qq33Hec89RPN4dpIqIFXf3h/nxfUXhWjJ5Knjg8LjY2NjYqxPUlhxYUUSk2NjY2tsZtP57wKg6kTh4UruV0R4vRfx31+HWM74s3DMPXAb7Q7jMKzmbFbcWFAP/i7AnDariZo91Fj+7x4daizCtu3/5625wDRZtXtxXpyyB3irpXerM+DcN2ZPpDzQtaa6EN7xy/x22z7UemjmgY5P6tekSn575/vqPHAF/szvLiyFlggC9Wex3xMx9uHlrALSp6ROdXV6cVqTsBAABKiADvtSIEeOeJX29zRRzRgnp+eezc+ej509CrnvtsVD2LppdvcOMj7/08a9mGLbvi08+9KmPtS21DcgKaHtlswJMfjP9z/qKFc6d+98aDvWrn/Eb0qD7j9uWq4nyQ1qOrVQ3RRLTAal3vefmLCX/Onj3tl09fvKtLtXNDZpq59qjZiXly+NEfb4nOKTqgSue7X/pi4sx/lixbtmjO1O/ffXxAs0jdlQfM9Z9eZfXdckse4M9J/21AkIiIqcboRbkzbcqUIVG6iGgBnd7b6yaeO09837ecJiJacI/PD3uf34vbU4ZhGNZFo10ThgUN+C3d6yXmtGfmvecvnddMkU0HPDNu9uaTWYW
</div>
</div>
</div>
<div id="conclusion" class="section level2">
<h2>Conclusion</h2>
<p>Scenario Bs constraints reduce the solvability of the puzzle
compared to Scenario A, as evident in the increased proportion of Low
solution counts. <strong>Clearly</strong>, the placement of pins has a
significant impact on the puzzles solvability, more so positively in an
unconstrained environment.</p>
</div>
</div>
</div>
</div>
<script>
// add bootstrap table styles to pandoc tables
function bootstrapStylePandocTables() {
$('tr.odd').parent('tbody').parent('table').addClass('table table-condensed');
}
$(document).ready(function () {
bootstrapStylePandocTables();
});
</script>
<!-- tabsets -->
<script>
$(document).ready(function () {
window.buildTabsets("TOC");
});
$(document).ready(function () {
$('.tabset-dropdown > .nav-tabs > li').click(function () {
$(this).parent().toggleClass('nav-tabs-open');
});
});
</script>
<!-- code folding -->
<script>
$(document).ready(function () {
// temporarily add toc-ignore selector to headers for the consistency with Pandoc
$('.unlisted.unnumbered').addClass('toc-ignore')
// move toc-ignore selectors from section div to header
$('div.section.toc-ignore')
.removeClass('toc-ignore')
.children('h1,h2,h3,h4,h5').addClass('toc-ignore');
// establish options
var options = {
selectors: "h1,h2,h3",
theme: "bootstrap3",
context: '.toc-content',
hashGenerator: function (text) {
return text.replace(/[.\\/?&!#<>]/g, '').replace(/\s/g, '_');
},
ignoreSelector: ".toc-ignore",
scrollTo: 0
};
options.showAndHide = true;
options.smoothScroll = true;
// tocify
var toc = $("#TOC").tocify(options).data("toc-tocify");
});
</script>
<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
(function () {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
document.getElementsByTagName("head")[0].appendChild(script);
})();
</script>
</body>
</html>