4092 lines
6.2 MiB
HTML
4092 lines
6.2 MiB
HTML
|
<!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,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
|
|||
|
}
|
|||
|
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='­<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 ";
|
|||
|
|
|||
|
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,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
|
|||
|
<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>It’s 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. It’s 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. It’s 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. It’s 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. It’s 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. It’s 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"><-</span> <span class="fu">fromJSON</span>(<span class="st">"../src/data_extended.json"</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"><-</span> data <span class="sc">%>%</span></span>
|
|||
|
<span id="cb5-2"><a href="#cb5-2" tabindex="-1"></a> <span class="fu">rowwise</span>() <span class="sc">%>%</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">%>%</span></span>
|
|||
|
<span id="cb5-11"><a href="#cb5-11" tabindex="-1"></a> <span class="fu">ungroup</span>() <span class="sc">%>%</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">"blue"</span>, <span class="at">color =</span> <span class="st">"black"</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">"Distribution of Solution Counts"</span>,</span>
|
|||
|
<span id="cb6-6"><a href="#cb6-6" tabindex="-1"></a> <span class="at">x =</span> <span class="st">"Solution Count"</span>,</span>
|
|||
|
<span id="cb6-7"><a href="#cb6-7" tabindex="-1"></a> <span class="at">y =</span> <span class="st">"Frequency"</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,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
|
|||
|
<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
|
|||
|
we’re using aggregated data for this analysis.</strong> (i.e., we’re
|
|||
|
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"><-</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"><-</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"><-</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"><-</span> data <span class="sc">%>%</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">"pinA_y"</span>, <span class="st">"pinA_x"</span>)) <span class="sc">%>%</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">"pinB_y"</span>, <span class="st">"pinB_x"</span>)) <span class="sc">%>%</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">"pinC_y"</span>, <span class="st">"pinC_x"</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,iVBORw0KGgoAAAANSUhEUgAABUAAAAPACAIAAAB7BESOAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAgAElEQVR4nOzdd3wUxf/H8dm9u/RKDb33Jr2pICCKIiiiAiKggogNsfeKDVH52sCCIiqC/kBApYhKEaT33jsJJYSElMuVnd8fFwIkl+RyuXA3yev5Fw+yd/fZmdm9fd/uzmpSSgEAAAAAAAKb7u8CAAAAAABAwQjwAAAAAAAogAAPAAAAAIACCPAAAAAAACiAAA8AAAAAgAII8AAAAAAAKIAADwAAAACAAgjwAAAAAAAogAAPAAAAAIACCPAAAAAAACiAAA8AAAAAgAII8AAAAAAAKIAADwAAAACAAgjwAAAAAAAogABfJM/UN2sF0k0RNTre9fLPO1NlHm+T+lO/UE3TNFOlBxfZrugKeFyMcWjCNcGapmlBbd/Z6fRjeTkEVNMVP+fR2Y+2KWPWs4ZWSI9J8XkNqjxk7J/3waie9aOz3+PSkRpUtnGvRz/5+0imr+u2LRxR0aRpmhbaf0a6r9/cLbUHhvPMuqnP9mtbPdJNN+nm2EY3P/bp4qPqrVbAch746uZyJlPcwF9OXbo9Ofe+3yGo4D28pmm6uUzT257/aev5nJuj2uPQj2yLHqxk8qjtc7M0fmGdw98rkEPmb0NidU3TTOXum1/MA8G5Z0KXSN1c6/7fzxTy2wEAoAgCfPGTRtqRVT+PHdCq6U1vLUss9m9U28ZvnxkzZsyYJ9+YtT+AknYRlLw18pJx6KvhQz9bn+T0chClb/lqUKurej81adHeFHfvIe1ndy749LGezdoO/3GPtWi1Xgklc2Bk7Jp6f6t6HYaN+3Xd0VQ33SSd53bN++SxHi06jpq+r6RkQr92pXH4m0eeXXA2pPNzb/aroHn1FtKZtH32u3d37Dhy1tGSMxShJFP9kW+PrK8d+u7hZ+clEeEBoCQy+7uAksHc+J73xnSJvuzYz5GRdDrh6K5Vixb8uyvRJoW0Hl7w8i03Js+a/173ct4dJXrEvvv3TybMsgpTdWef5/vVMRXfJ10pJW+NvGMcmTNtSYoUQgtuPPSzSc/dUL9MeGRZT4eSc9/kgTeO+i3eKYUQWli1Drf0v6Vrm0bVy0da7KlnEw5sX7vkt1kLN5/KlEbK1m+G9kjVl/84sHpAN3bJGxgyacVb/W57delpQwohhBZcsXmPm7q3rFs1LtaSee7k4R3rVyxeuuF4uhTSSNrwxZAbzmuLv7srsHvJI37sSpk49+XXFiZpVYY/f1/dvD7YVOv215/vFZfjB29pT0+K37v+7zm//XckXQoh07Z/PWxg3XqLn2lmKfa6Szhzk3s+/Kpteu78acTPe/u1WYecQpjr3PnGcz3d/OSix7Soqf42UQShHUc/2eOrkQu/f/a9Ed3e7RDq73oAAL4mUQRP13MdJgRfPyneyGsh65FF7/ZvEJ51mKFXuG3qMeflSzjP7t+wbt26des3H07J8208lfpTvxAhhDBVf3SJzYvXuy/GefCjq4OEEMLS5u0djqLWWDj5rZFPmy7A2f4dU8tU4HBzz3lk8s1lXPFDL9P5md8OZrhbKm3PzDEdYrMWK9tnSs6B6rXMBcMr6EIIEXL79DQfvWfJGxi23RN7uZpJaKaybUZ8ufq0PddC9jObpz15bUWzltVLN399yFe95EdF3Wt5L3PNC00smhbU5q3tufZrjj3j2ruSuKXdu7vz3u1lHvnjqQ4xWeleL3/n9FPZQ07FcRjYHDvebuPqlKBO4/cpM/atc++J0YQQetl752Vegc9LXTSqukloEd0+PaBMGwEAPMUl9MUvuFqPZ2csm/V4ywhNCGGcmvPsUzNPXnZiQY+t3bJ169atWzWvHlmM5+Y9E1DFFEitaovI6XBdnatFRhdyZZ17fpz051lDCGGqNuTb2e/2rhnibrGwev0++OOH+2qZhBBG4ry3P16r7CXa6g0Mx86Phz+z4JQhhGaucstny/79ckS7crkvkTKXbT5w/J+LJ9xQXhdCGInzXx27MPXKV1tCyNOz3v9yp12EdR0xpKHXJ22Dqt303sxP+pbThRDCODP/57+SL/xJvXGIEiG864ghjcwydemEj5dn+LsYAICPEeCvDL1Cz3E/vtopXBNCGAmz3v9mFzdK4oqRp5f+s8UuhBDmOgMe7JXfHRxamRtfGN0pWBNCOA7M+2NHoM0FVVLJhOkvvrPivBRCC2r8xM/TRjZ2+xNLluBGD3720rVhmhDCOPHLF7+e4k5Xrzj3fDthbqKhxfS6r3+VIn0Z6pXveKh/JV0IIWT6upWb7b4pEPCSufnQoW2DNOf+KRNmnWb/AAAlC/fAXzHmRg+/PeKLbhP2OaVt49Tv1j/1brsL90k6d80c9/M2m9QiWg9+vHdtNyeCZEbC9rWrNuw4ciop1RkSXb5q/RbtOrSsEXnJMaeRsPiLr5adMuzbdjqEEEImr/lu7OtLdHHJuxqH5388dU2yYarW86F7O5bRhBAZh/+b/8/andu3h/T97MlrLJ4Uc6Gm9KNr//l3y6ETZzKCylaq0bB9l471YtwPqIxN0z6cs9ch9HKd7xvVw+2RsnPP7PHTN1ulFtZy0BN96po8XCPPqrUn7vpv2bo9xxIS083RFeJqNO54TZsakXmtmnFs0Wff/nfW0Ct2eeCBrhV1kXF87Z9z/1i8OcERUb5SXIW4Gk3aX9u5acXgPJvGMx5XZd380wez9ziMw2uSpRBCOHbOfOf13RYhzLV7j76ndUSBn+RMOJ7g+sVIr1yjSgEnGvVqHTvWMP27xyGMhOMJRlGLzxcD48Ja7pg84Q/XJRI17//oxU7hBb3AVOvu+69/aemc81KmLPl96fl77ogq+gp61x0u3jWOJ115kQe7wUKxb/r+u/WZUovp0f+G2KKeHw9q3LyhRRzPFMI4k3DKIYRFiLzHoW/Gkq8b5IKA2S684snX3GWcKYc3/rdq66GTiUmpzqCImAo16jdr3a551XAP2lGmH1u/dPmWgydOp+oxcVXrtLjmmhZerKlxevk3X/5z3CGF0KNaDnioT72c71HovjbVvu32Ni+u+i954be/HB34UHXO1gBACeLva/jV5tE98BfZ173Q2JVwzQ2fW3Px9lbrzAHhmhBCjxv5Z87b44yUbdOe6d0o1pzj+FLTI2tfP+aHrdk3Vto3vNTEbXzWK45YmPWutsWPVDMJISwd39/rlMbZf9+5qWaoJoQQWuzQ36z5FHP5PfCO+MXv9GsYbbqsJi24YrthHy+Lz30Lq3Hmm17BQghhbvDs6tx39bo+Nvctgp6sUX5NJ6U0zu+a+cqtjWNytV5wXLuhH/x12O2d4LaVT9U1CSHMzV/dZE/b9eOIFlE5j3204LiOD36zKdm7u1oLW9XZKb3dHxEGd594wpMSHJtfa+FqSVO1BxcVeBN6+pENy5YsWbJk6fKdZ3K9vVdNmsc98AyMLPb1L17YM7R4bbNnc0w4T8x9afCAAQMGDBj0+A97cr7GmxX0sjtcvGscT7pSykLsBgsjc9noWiYhtKh+0866fb2n98C7Sjw+sXvWZhpy648pF9orj3FY1LFULA0ScNuFOwXfA+/J19yF1d0587W7ripnyfXrjaaH1+jy4MRVp/O+gdxI2jT18R61IvTLvwbN0fV6PT19e84OyO8eeOPM4mfbRrkqjGj15KLTl7/W677OGr9aUIdxuXYQAACVEeCLpJABXtqWjc6aHTeo6ydHsg8N8gwbzvg/Hmkens+pIT2m89jV56WUUjq2vNulalxcXMWYENeRgCmsTFxcXFxc5WZPXZgX6pIjmz1JK1/vGJN9nFWIAP/Ggu8H1sh9xJP1PpZqt07cmiMiehkMPFmj/HKa49jcR66KyLv1NL181zeWJ+bquIvHoy/Pn353dVNe76CX7T5hW6HnI/KiqnMz7qkRFxcXVybMVYsWElMxLi4uLq76Hd8leHRInPLLXVnPSNDCWjz6+zFv5wnztkl9G+BL3MC4mEksrcfmnkut0LxcQR8F+MI0jiddWajdYCHYVj5VzySE
|
|||
|
<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, that’s 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">\(< 3\)</span>, the solution count is generally
|
|||
|
higher. This suggests that the <code>pinB</code> track might have a more
|
|||
|
significant impact on the puzzle’s solvability.</p>
|
|||
|
<p>Considering this interesting development, let’s 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 it’s 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>It’s 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>Let’s 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 they’re 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"><-</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"><-</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"><-</span> data <span class="sc">%>%</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">>=</span> high_threshold_A <span class="sc">~</span> <span class="st">"High"</span>,</span>
|
|||
|
<span id="cb9-7"><a href="#cb9-7" tabindex="-1"></a> solution_count <span class="sc"><=</span> low_threshold_A <span class="sc">~</span> <span class="st">"Low"</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">"Medium"</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"><-</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"><-</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"><-</span> valid_scenarioB <span class="sc">%>%</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">>=</span> high_threshold_B <span class="sc">~</span> <span class="st">"High"</span>,</span>
|
|||
|
<span id="cb9-17"><a href="#cb9-17" tabindex="-1"></a> solution_count <span class="sc"><=</span> low_threshold_B <span class="sc">~</span> <span class="st">"Low"</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">"Medium"</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"><-</span> data <span class="sc">%>%</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">%>%</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">'drop'</span>) <span class="sc">%>%</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
|
|||
|
## <chr> <int> <dbl>
|
|||
|
## 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"><-</span> valid_scenarioB <span class="sc">%>%</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">%>%</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">'drop'</span>) <span class="sc">%>%</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
|
|||
|
## <chr> <int> <dbl>
|
|||
|
## 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,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
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="conclusion" class="section level2">
|
|||
|
<h2>Conclusion</h2>
|
|||
|
<p>Scenario B’s 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 puzzle’s 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>
|