diff --git a/docs/user/api/v2.rst b/docs/user/api/v2.rst index 367b4224d96..8cc60df58f4 100644 --- a/docs/user/api/v2.rst +++ b/docs/user/api/v2.rst @@ -330,6 +330,11 @@ Embed Retrieve HTML-formatted content from documentation page or section. + .. warning:: + + The content will be returned as is, without any sanitization or escaping. + You should not include content from arbitrary projects, or projects you do not trust. + **Example request**: .. prompt:: bash $ diff --git a/docs/user/api/v3.rst b/docs/user/api/v3.rst index 3783b3c5cd5..7b06b4fb2df 100644 --- a/docs/user/api/v3.rst +++ b/docs/user/api/v3.rst @@ -1927,6 +1927,10 @@ Embed Passing ``?doctool=`` and ``?doctoolversion=`` may improve the response, since the endpoint will know more about the exact structure of the HTML and can make better decisions. + .. warning:: + + The content will be returned as is, without any sanitization or escaping. + You should not include content from arbitrary projects, or projects you do not trust. Additional APIs --------------- diff --git a/docs/user/server-side-search/api.rst b/docs/user/server-side-search/api.rst index 98711621fa0..18a36f5ddf2 100644 --- a/docs/user/server-side-search/api.rst +++ b/docs/user/server-side-search/api.rst @@ -30,16 +30,18 @@ API v3 :>json string domain: Canonical domain of the resulting page :>json string path: Path to the resulting page :>json object highlights: An object containing a list of substrings with matching terms. - Note that the text is HTML escaped with the matching terms inside a tag. + Note that the text is HTML escaped with the matching terms inside a ```` tag. :>json object blocks: A list of block objects containing search results from the page. - Currently, there are two types of blocks: + Currently, there is one type of block: - section: A page section with a linkable anchor (``id`` attribute). - - domain: A Sphinx :doc:`domain ` - with a linkable anchor (``id`` attribute). + .. warning:: + + Except for highlights, any other content is not HTML escaped, + you shouldn't include it in your page without escaping it first. **Example request**: @@ -198,16 +200,18 @@ API v2 (deprecated) :>json string domain: Canonical domain of the resulting page :>json string path: Path to the resulting page :>json object highlights: An object containing a list of substrings with matching terms. - Note that the text is HTML escaped with the matching terms inside a tag. + Note that the text is HTML escaped with the matching terms inside a ```` tag. :>json object blocks: A list of block objects containing search results from the page. - Currently, there are two types of blocks: + Currently, there is one type of block: - section: A page section with a linkable anchor (``id`` attribute). - - domain: A Sphinx :doc:`domain ` - with a linkable anchor (``id`` attribute). + .. warning:: + + Except for highlights, any other content is not HTML escaped, + you shouldn't include it in your page without escaping it first. **Example request**: @@ -265,17 +269,6 @@ API v2 (deprecated) "You can search all projects at https://readthedocs.org/search/" ] } - }, - { - "type": "domain", - "role": "http:get", - "name": "/_/api/v2/search/", - "id": "get--_-api-v2-search-", - "content": "Retrieve search results for docs", - "highlights": { - "name": [""], - "content": ["Retrieve search results for docs"] - } } ] }, diff --git a/readthedocs/core/static-src/core/js/doc-embed/search.js b/readthedocs/core/static-src/core/js/doc-embed/search.js index 52b12eaf3e2..e5af0cec65f 100644 --- a/readthedocs/core/static-src/core/js/doc-embed/search.js +++ b/readthedocs/core/static-src/core/js/doc-embed/search.js @@ -3,16 +3,50 @@ */ const rtddata = require('./rtd-data'); -const xss = require('xss/lib/index'); const { createDomNode, domReady } = require("./utils"); const MAX_RESULT_PER_SECTION = 3; const MAX_SUBSTRING_LIMIT = 100; +/** + * Mark a string as safe to be used as HTML in setNodeContent. + * @class + */ +function SafeHtmlString(value) { + this.value = value; + this.isSafe = true; +} + +/** + * Create a SafeHtmlString instance from a string. + * + * @param {String} value + */ +function markAsSafe(value) { + return new SafeHtmlString(value); +} + +/** + * Set the content of an element as text or HTML. + * + * @param {Element} element + * @param {String|SafeHtmlString} content + */ +function setElementContent(element, content) { + if (content.isSafe) { + element.innerHTML = content.value; + } else { + element.innerText = content; + } +} + /* * Search query override for hitting our local API instead of the standard * Sphinx indexer. This will fall back to the standard indexer on an API - * failure, + * failure. + * + * Except for highlights, which are HTML encoded, with `` tags surrounding the highlight, + * all other data shouldn't be considered safe to be used as HTML. */ function attach_elastic_search_query_sphinx(data) { var project = data.project; @@ -54,20 +88,22 @@ function attach_elastic_search_query_sphinx(data) { * * ... * - * @param {String} title. + * @param {String|SafeHtmlString} title. * @param {String} link. - * @param {Array} contents. + * @param {String[]|SafeHtmlString[]} contents. */ + // Watch our for XSS in title and contents! const buildSection = function (title, link, contents) { var div_title = document.createElement("div"); var a_element = document.createElement("a"); a_element.href = link; - a_element.innerHTML = title; + setElementContent(a_element, title); + div_title.appendChild(a_element); let elements = [div_title]; for (let content of contents) { let div_content = document.createElement("div"); - div_content.innerHTML = content; + setElementContent(div_content, content); elements.push(div_content); } return elements; @@ -94,13 +130,13 @@ function attach_elastic_search_query_sphinx(data) { var title = result.title; // if highlighted title is present, use that. if (result.highlights.title.length) { - title = xss(result.highlights.title[0]); + title = markAsSafe(result.highlights.title[0]); } var link = result.path + "?highlight=" + encodeURIComponent(query); let item = createDomNode('a', {href: link}); - item.innerHTML = title; + setElementContent(item, title); for (let element of item.getElementsByTagName('span')) { element.className = 'highlighted'; } @@ -126,7 +162,7 @@ function attach_elastic_search_query_sphinx(data) { var section_content = [section.content.substr(0, MAX_SUBSTRING_LIMIT) + " ..."]; if (section.highlights.title.length) { - section_subtitle = xss(section.highlights.title[0]); + section_subtitle = markAsSafe(section.highlights.title[0]); } if (section.highlights.content.length) { @@ -137,7 +173,7 @@ function attach_elastic_search_query_sphinx(data) { k < content.length && k < MAX_RESULT_PER_SECTION; k += 1 ) { - section_content.push("... " + xss(content[k]) + " ..."); + section_content.push(markAsSafe("... " + content[k] + " ...")); } } let sections = buildSection( @@ -148,36 +184,6 @@ function attach_elastic_search_query_sphinx(data) { sections.forEach(element => { contents.appendChild(element); }); } - // if the result is a sphinx domain object - if (current_block.type === "domain") { - var domain = current_block; - var domain_role_name = domain.role; - var domain_subtitle_link = link + "#" + domain.id; - var domain_name = domain.name; - var domain_content = ""; - - if (domain.content !== "") { - domain_content = domain.content.substr(0, MAX_SUBSTRING_LIMIT) + " ..."; - } - - if (domain.highlights.content.length) { - domain_content = "... " + xss(domain.highlights.content[0]) + " ..."; - } - - if (domain.highlights.name.length) { - domain_name = xss(domain.highlights.name[0]); - } - - var domain_subtitle = "[" + domain_role_name + "]: " + domain_name; - - let sections = buildSection( - domain_subtitle, - domain_subtitle_link, - [domain_content] - ); - sections.forEach(element => { contents.appendChild(element); }); - } - for (let element of contents.getElementsByTagName('span')) { element.className = 'highlighted'; } diff --git a/readthedocs/core/static/core/js/readthedocs-doc-embed.js b/readthedocs/core/static/core/js/readthedocs-doc-embed.js index eb119fc46dd..fe6a0f43f1c 100644 --- a/readthedocs/core/static/core/js/readthedocs-doc-embed.js +++ b/readthedocs/core/static/core/js/readthedocs-doc-embed.js @@ -1 +1 @@ -!function n(r,o,a){function s(t,e){if(!o[t]){if(!r[t]){var i="function"==typeof require&&require;if(!e&&i)return i(t,!0);if(l)return l(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}i=o[t]={exports:{}},r[t][0].call(i.exports,function(e){return s(r[t][1][e]||e)},i,i.exports,n,r,o,a)}return o[t].exports}for(var l="function"==typeof require&&require,e=0;e"),i("table.docutils.footnote").wrap("
"),i("table.docutils.citation").wrap("
"),i(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var t=i(this);(expand=i('')).on("click",function(e){return n.toggleCurrent(t),e.stopPropagation(),!1}),t.prepend(expand)})},reset:function(){var e=encodeURI(window.location.hash)||"#";try{var t,i=$(".wy-menu-vertical"),n=i.find('[href="'+e+'"]');0===n.length&&(t=$('.document [id="'+e.substring(1)+'"]').closest("div.section"),0===(n=i.find('[href="#'+t.attr("id")+'"]')).length&&(n=i.find('[href="#"]'))),0this.docHeight||(this.navBar.scrollTop(i),this.winPosition=e)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},toggleCurrent:function(e){e=e.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:t.exports.ThemeNav,StickyNav:t.exports.ThemeNav});for(var o=0,r=["ms","moz","webkit","o"],a=0;a/g,u=/"/g,h=/"/g,p=/&#([a-zA-Z0-9]*);?/gim,f=/:?/gim,g=/&newline;?/gim,m=/((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a)\:/gi,v=/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi,b=/u\s*r\s*l\s*\(.*/gi;function w(e){return e.replace(u,""")}function y(e){return e.replace(h,'"')}function _(e){return e.replace(p,function(e,t){return"x"===t[0]||"X"===t[0]?String.fromCharCode(parseInt(t.substr(1),16)):String.fromCharCode(parseInt(t,10))})}function x(e){return e.replace(f,":").replace(g," ")}function T(e){for(var t="",i=0,n=e.length;i/g;i.whiteList=o(),i.getDefaultWhiteList=o,i.onTag=function(e,t,i){},i.onIgnoreTag=function(e,t,i){},i.onTagAttr=function(e,t,i){},i.onIgnoreTagAttr=function(e,t,i){},i.safeAttrValue=function(e,t,i,n){if(i=E(i),"href"===t||"src"===t){if("#"===(i=d.trim(i)))return"#";if("http://"!==i.substr(0,7)&&"https://"!==i.substr(0,8)&&"mailto:"!==i.substr(0,7)&&"tel:"!==i.substr(0,4)&&"#"!==i[0]&&"/"!==i[0])return""}else if("background"===t){if(m.lastIndex=0,m.test(i))return""}else if("style"===t){if(v.lastIndex=0,v.test(i))return"";if(b.lastIndex=0,b.test(i)&&(m.lastIndex=0,m.test(i)))return"";!1!==n&&(i=(n=n||a).process(i))}return i=k(i)},i.escapeHtml=s,i.escapeQuote=w,i.unescapeQuote=y,i.escapeHtmlEntities=_,i.escapeDangerHtml5Entities=x,i.clearNonPrintableCharacter=T,i.friendlyAttrValue=E,i.escapeAttrValue=k,i.onIgnoreTagStripAll=function(){return""},i.StripTagBody=function(o,a){"function"!=typeof a&&(a=function(){});var s=!Array.isArray(o),l=[],c=!1;return{onIgnoreTag:function(e,t,i){var n,r;return r=e,s||-1!==d.indexOf(o,r)?i.isClosing?(n=i.position+(r="[/removed]").length,l.push([!1!==c?c:i.position,n]),c=!1,r):(c=c||i.position,"[removed]"):a(e,t,i)},remove:function(t){var i="",n=0;return d.forEach(l,function(e){i+=t.slice(n,e[0]),n=e[1]}),i+=t.slice(n)}}},i.stripCommentTag=function(e){return e.replace(A,"")},i.stripBlankChar=function(e){return e.split("").filter(function(e){e=e.charCodeAt(0);return 127!==e&&(!(e<=31)||(10===e||13===e))}).join("")},i.cssFilter=a,i.getDefaultCSSWhiteList=r},{"./util":5,cssfilter:9}],3:[function(e,t,i){var n,r=e("./default"),o=e("./parser"),a=e("./xss");for(n in(i=t.exports=function(e,t){return new a(t).process(e)}).FilterXSS=a,r)i[n]=r[n];for(n in o)i[n]=o[n];"undefined"!=typeof window&&(window.filterXSS=t.exports)},{"./default":2,"./parser":4,"./xss":6}],4:[function(e,t,i){var f=e("./util");var d=/[^a-zA-Z0-9_:\.\-]/gim;function u(e){return'"'===(t=e)[0]&&'"'===t[t.length-1]||"'"===t[0]&&"'"===t[t.length-1]?e.substr(1,e.length-2):e;var t}i.parseTag=function(e,t,i){for(var n,r,o,a="",s=0,l=!1,c=!1,d=0,u=e.length,h="",d=0;d"===p?(a+=i(e.slice(s,l)),n=e.slice(l,d+1),r=n,o=void 0,o=f.spaceIndex(r),r=-1===o?r.slice(1,-1):r.slice(1,o+1),h=r="/"===(r="/"===(r=f.trim(r).toLowerCase()).slice(0,1)?r.slice(1):r).slice(-1)?r.slice(0,-1):r,a+=t(l,a.length,h,n,"";n=i;var n=-1===(a=m.spaceIndex(n))?{html:"",closing:"/"===n[n.length-2]}:{html:n=(a="/"===(n=m.trim(n.slice(a+1,-1)))[n.length-1])?m.trim(n.slice(0,-1)):n,closing:a},o=s[r],a=g(n.html,function(e,t){var i=-1!==m.indexOf(o,e),n=d(r,e,t,i);return v(n)?i?(t=h(r,e,t,f))?e+'="'+t+'"':e:v(n=u(r,e,t,i))?void 0:n:n}),i="<"+r;return a&&(i+=" "+a),n.closing&&(i+=" /"),i+=">"}return v(t=c(r,i,e))?p(i):t},p));return t=i?i.remove(t):t},t.exports=s},{"./default":2,"./parser":4,"./util":5,cssfilter:9}],7:[function(e,t,i){var n=e("./default"),r=e("./parser");e("./util");function u(e){return null==e}function o(e){(e=e||{}).whiteList=e.whiteList||n.whiteList,e.onAttr=e.onAttr||n.onAttr,e.onIgnoreAttr=e.onIgnoreAttr||n.onIgnoreAttr,this.options=e}o.prototype.process=function(e){if(!(e=(e=e||"").toString()))return"";var t=this.options,l=t.whiteList,c=t.onAttr,d=t.onIgnoreAttr;return r(e,function(e,t,i,n,r){var o,a=l[i],s=!1,a=(!0===a?s=a:"function"==typeof a?s=a(n):a instanceof RegExp&&(s=a.test(n)),{position:t,sourcePosition:e,source:r,isWhite:s=!0!==s?!1:s});return s?u(o=c(i,n,a))?i+":"+n:o:u(o=d(i,n,a))?void 0:o})},t.exports=o},{"./default":8,"./parser":10,"./util":11}],8:[function(e,t,i){function n(){var e={"align-content":!1,"align-items":!1,"align-self":!1,"alignment-adjust":!1,"alignment-baseline":!1,all:!1,"anchor-point":!1,animation:!1,"animation-delay":!1,"animation-direction":!1,"animation-duration":!1,"animation-fill-mode":!1,"animation-iteration-count":!1,"animation-name":!1,"animation-play-state":!1,"animation-timing-function":!1,azimuth:!1,"backface-visibility":!1,background:!0,"background-attachment":!0,"background-clip":!0,"background-color":!0,"background-image":!0,"background-origin":!0,"background-position":!0,"background-repeat":!0,"background-size":!0,"baseline-shift":!1,binding:!1,bleed:!1,"bookmark-label":!1,"bookmark-level":!1,"bookmark-state":!1,border:!0,"border-bottom":!0,"border-bottom-color":!0,"border-bottom-left-radius":!0,"border-bottom-right-radius":!0,"border-bottom-style":!0,"border-bottom-width":!0,"border-collapse":!0,"border-color":!0,"border-image":!0,"border-image-outset":!0,"border-image-repeat":!0,"border-image-slice":!0,"border-image-source":!0,"border-image-width":!0,"border-left":!0,"border-left-color":!0,"border-left-style":!0,"border-left-width":!0,"border-radius":!0,"border-right":!0,"border-right-color":!0,"border-right-style":!0,"border-right-width":!0,"border-spacing":!0,"border-style":!0,"border-top":!0,"border-top-color":!0,"border-top-left-radius":!0,"border-top-right-radius":!0,"border-top-style":!0,"border-top-width":!0,"border-width":!0,bottom:!1,"box-decoration-break":!0,"box-shadow":!0,"box-sizing":!0,"box-snap":!0,"box-suppress":!0,"break-after":!0,"break-before":!0,"break-inside":!0,"caption-side":!1,chains:!1,clear:!0,clip:!1,"clip-path":!1,"clip-rule":!1,color:!0,"color-interpolation-filters":!0,"column-count":!1,"column-fill":!1,"column-gap":!1,"column-rule":!1,"column-rule-color":!1,"column-rule-style":!1,"column-rule-width":!1,"column-span":!1,"column-width":!1,columns:!1,contain:!1,content:!1,"counter-increment":!1,"counter-reset":!1,"counter-set":!1,crop:!1,cue:!1,"cue-after":!1,"cue-before":!1,cursor:!1,direction:!1,display:!0,"display-inside":!0,"display-list":!0,"display-outside":!0,"dominant-baseline":!1,elevation:!1,"empty-cells":!1,filter:!1,flex:!1,"flex-basis":!1,"flex-direction":!1,"flex-flow":!1,"flex-grow":!1,"flex-shrink":!1,"flex-wrap":!1,float:!1,"float-offset":!1,"flood-color":!1,"flood-opacity":!1,"flow-from":!1,"flow-into":!1,font:!0,"font-family":!0,"font-feature-settings":!0,"font-kerning":!0,"font-language-override":!0,"font-size":!0,"font-size-adjust":!0,"font-stretch":!0,"font-style":!0,"font-synthesis":!0,"font-variant":!0,"font-variant-alternates":!0,"font-variant-caps":!0,"font-variant-east-asian":!0,"font-variant-ligatures":!0,"font-variant-numeric":!0,"font-variant-position":!0,"font-weight":!0,grid:!1,"grid-area":!1,"grid-auto-columns":!1,"grid-auto-flow":!1,"grid-auto-rows":!1,"grid-column":!1,"grid-column-end":!1,"grid-column-start":!1,"grid-row":!1,"grid-row-end":!1,"grid-row-start":!1,"grid-template":!1,"grid-template-areas":!1,"grid-template-columns":!1,"grid-template-rows":!1,"hanging-punctuation":!1,height:!0,hyphens:!1,icon:!1,"image-orientation":!1,"image-resolution":!1,"ime-mode":!1,"initial-letters":!1,"inline-box-align":!1,"justify-content":!1,"justify-items":!1,"justify-self":!1,left:!1,"letter-spacing":!0,"lighting-color":!0,"line-box-contain":!1,"line-break":!1,"line-grid":!1,"line-height":!1,"line-snap":!1,"line-stacking":!1,"line-stacking-ruby":!1,"line-stacking-shift":!1,"line-stacking-strategy":!1,"list-style":!0,"list-style-image":!0,"list-style-position":!0,"list-style-type":!0,margin:!0,"margin-bottom":!0,"margin-left":!0,"margin-right":!0,"margin-top":!0,"marker-offset":!1,"marker-side":!1,marks:!1,mask:!1,"mask-box":!1,"mask-box-outset":!1,"mask-box-repeat":!1,"mask-box-slice":!1,"mask-box-source":!1,"mask-box-width":!1,"mask-clip":!1,"mask-image":!1,"mask-origin":!1,"mask-position":!1,"mask-repeat":!1,"mask-size":!1,"mask-source-type":!1,"mask-type":!1,"max-height":!0,"max-lines":!1,"max-width":!0,"min-height":!0,"min-width":!0,"move-to":!1,"nav-down":!1,"nav-index":!1,"nav-left":!1,"nav-right":!1,"nav-up":!1,"object-fit":!1,"object-position":!1,opacity:!1,order:!1,orphans:!1,outline:!1,"outline-color":!1,"outline-offset":!1,"outline-style":!1,"outline-width":!1,overflow:!1,"overflow-wrap":!1,"overflow-x":!1,"overflow-y":!1,padding:!0,"padding-bottom":!0,"padding-left":!0,"padding-right":!0,"padding-top":!0,page:!1,"page-break-after":!1,"page-break-before":!1,"page-break-inside":!1,"page-policy":!1,pause:!1,"pause-after":!1,"pause-before":!1,perspective:!1,"perspective-origin":!1,pitch:!1,"pitch-range":!1,"play-during":!1,position:!1,"presentation-level":!1,quotes:!1,"region-fragment":!1,resize:!1,rest:!1,"rest-after":!1,"rest-before":!1,richness:!1,right:!1,rotation:!1,"rotation-point":!1,"ruby-align":!1,"ruby-merge":!1,"ruby-position":!1,"shape-image-threshold":!1,"shape-outside":!1,"shape-margin":!1,size:!1,speak:!1,"speak-as":!1,"speak-header":!1,"speak-numeral":!1,"speak-punctuation":!1,"speech-rate":!1,stress:!1,"string-set":!1,"tab-size":!1,"table-layout":!1,"text-align":!0,"text-align-last":!0,"text-combine-upright":!0,"text-decoration":!0,"text-decoration-color":!0,"text-decoration-line":!0,"text-decoration-skip":!0,"text-decoration-style":!0,"text-emphasis":!0,"text-emphasis-color":!0,"text-emphasis-position":!0,"text-emphasis-style":!0,"text-height":!0,"text-indent":!0,"text-justify":!0,"text-orientation":!0,"text-overflow":!0,"text-shadow":!0,"text-space-collapse":!0,"text-transform":!0,"text-underline-position":!0,"text-wrap":!0,top:!1,transform:!1,"transform-origin":!1,"transform-style":!1,transition:!1,"transition-delay":!1,"transition-duration":!1,"transition-property":!1,"transition-timing-function":!1,"unicode-bidi":!1,"vertical-align":!1,visibility:!1,"voice-balance":!1,"voice-duration":!1,"voice-family":!1,"voice-pitch":!1,"voice-range":!1,"voice-rate":!1,"voice-stress":!1,"voice-volume":!1,volume:!1,"white-space":!1,widows:!1,width:!0,"will-change":!1,"word-break":!0,"word-spacing":!0,"word-wrap":!0,"wrap-flow":!1,"wrap-through":!1,"writing-mode":!1,"z-index":!1};return e}i.whiteList=n(),i.getDefaultWhiteList=n,i.onAttr=function(e,t,i){},i.onIgnoreAttr=function(e,t,i){}},{}],9:[function(e,t,i){var n,r=e("./default"),o=e("./css");for(n in(i=t.exports=function(e,t){return new o(t).process(e)}).FilterCSS=o,r)i[n]=r[n];"undefined"!=typeof window&&(window.filterCSS=t.exports)},{"./css":7,"./default":8}],10:[function(e,t,i){var d=e("./util");t.exports=function(n,r){";"!==(n=d.trimRight(n))[n.length-1]&&(n+=";");var e=n.length,o=!1,a=0,s=0,l="";function t(){var e,t,i;o||-1!==(t=(e=d.trim(n.slice(a,s))).indexOf(":"))&&(i=d.trim(e.slice(0,t)),t=d.trim(e.slice(t+1)),i&&(i=r(a,l.length,i,t,e))&&(l+=i+"; ")),a=s+1}for(;s{if(e.ok)return e.json();throw new Error}).then(t=>{t.show_version_warning&&o.init(t.version_compare);{var i=r.get();let e=document.querySelector(a);if(null!==e)e.innerHTML=t.html;else if(i.is_sphinx_builder()&&i.is_rtd_like_theme()){let e=document.querySelector("div.rst-other-versions");null!==e&&(e.innerHTML=t.html)}else document.body.insertAdjacentHTML("beforeend",t.html);if(t.version_active)t.version_supported;else for(var n of document.getElementsByClassName("rst-current-version"))n.classList.add("rst-out-of-date");return}}).catch(e=>{console.error("Error loading Read the Docs footer")}),{project:t.project,version:t.version,absolute_uri:window.location.href}),t=t.proxied_api_host+"/api/v2/analytics/?"+new URLSearchParams(e).toString();fetch(t,{method:"GET",cache:"no-store"}).then(e=>{if(!e.ok)throw new Error}).catch(e=>{console.error("Error registering page view")})}}},{"./rtd-data":14,"./version-compare":19}],14:[function(e,t,i){var n=e("./constants"),r={is_rtd_like_theme:function(){return 1===document.querySelectorAll("div.rst-other-versions").length||(this.theme===n.THEME_RTD||this.theme===n.THEME_MKDOCS_RTD)},is_alabaster_like_theme:function(){return-1{if(e.ok)return e.json();throw new Error}).then(e=>{if(0{t.appendChild(e)})}if("domain"===u.type){var h=u,p=h.role,f=l+"#"+h.id,u=h.name,b="",u=(""!==h.content&&(b=h.content.substr(0,C)+" ..."),h.highlights.content.length&&(b="... "+k(h.highlights.content[0])+" ..."),"["+p+"]: "+(u=h.highlights.name.length?k(h.highlights.name[0]):u));let e=y(u,f,[b]);e.forEach(e=>{t.appendChild(e)})}for(d of t.getElementsByTagName("span"))d.className="highlighted";i.appendChild(t),c{T()})}var i,E=t.project,n=t.version,r=t.language||"en";"undefined"!=typeof Search&&E&&n&&(t.features&&t.features.docsearch_disabled?console.log("Server side search is disabled."):(i=Search.query,Search.query_fallback=i,Search.query=e)),o(function(){"undefined"!=typeof Search&&Search.init()})}t.exports={init:function(){var e=n.get();e.is_sphinx_builder()?r(e):console.log("Server side search is disabled.")}}},{"./../../../../../../bower_components/xss/lib/index":3,"./rtd-data":14,"./utils":18}],16:[function(n,e,t){const r=n("./rtd-data"),o=n("./utils")["domReady"];e.exports={init:function(){var e,t=r.get(),i=document.querySelector("[data-toggle='rst-current-version']");null!=i&&i.addEventListener("click",function(){var e=$("[data-toggle='rst-versions']").hasClass("shift-up")?"was_open":"was_closed";"undefined"!=typeof READTHEDOCS_DATA&&READTHEDOCS_DATA.global_analytics_code&&("undefined"!=typeof gtag?gtag("event","Click",{event_category:"Flyout",event_label:e,send_to:"rtfd"}):"undefined"!=typeof ga?ga("rtfd.send","event","Flyout","Click",e):"undefined"!=typeof _gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Flyout","Click",e]))}),void 0===window.SphinxRtdTheme&&(e=n("./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js").ThemeNav,o(function(){setTimeout(function(){e.navBar||e.enable()},1e3)}),t.is_rtd_like_theme()&&!$("div.wy-side-scroll:first").length&&(console.log("Applying theme sidebar fix..."),i=$("nav.wy-nav-side:first"),t=$("
").addClass("wy-side-scroll"),i.children().detach().appendTo(t),t.prependTo(i),e.navBar=t))}}},{"./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js":1,"./rtd-data":14,"./utils":18}],17:[function(e,t,i){e("./constants");var s,l=e("./rtd-data"),c="[data-ea-publisher]",d="#ethical-ad-placement";function u(){var e=!1;return $("
").attr("id","rtd-detection").attr("class","ethical-rtd").html(" ").appendTo("body"),0===$("#rtd-detection").height()&&(e=!0),$("#rtd-detection").remove(),e}function h(){console.log("---------------------------------------------------------------------------------------"),console.log("Read the Docs hosts documentation for tens of thousands of open source projects."),console.log("We fund our development (we are open source) and operations through advertising."),console.log("We promise to:"),console.log(" - never let advertisers run 3rd party JavaScript"),console.log(" - never sell user data to advertisers or other 3rd parties"),console.log(" - only show advertisements of interest to developers"),console.log("Read more about our approach to advertising here: https://docs.readthedocs.io/en/latest/advertising/ethical-advertising.html"),console.log("%cPlease allow our Ethical Ads or go ad-free:","font-size: 2em"),console.log("https://docs.readthedocs.io/en/latest/advertising/ad-blocking.html"),console.log("--------------------------------------------------------------------------------------")}function p(e){e&&(e=e.attr("class","keep-us-sustainable"),$("

").text("Support Read the Docs!").appendTo(e),$("

").html('Please help keep us sustainable by allowing our Ethical Ads in your ad blocker or go ad-free by subscribing.').appendTo(e),$("

").text("Thank you! ❤️").appendTo(e))}t.exports={init:function(){var t,e,i,n,r,o,a;(s=l.get()).show_promo()&&(r=null,o="readthedocs-sidebar",t=0<$(c).length?($(c).attr("data-ea-publisher","readthedocs"),$(c).attr("data-ea-manual","true"),"image"!==$(c).attr("data-ea-type")&&"text"!==$(c).attr("data-ea-type")&&$(c).attr("data-ea-type","readthedocs-sidebar"),$(c)):(0<$(d).length?(r=d,e=s.is_rtd_like_theme()?"ethical-rtd ethical-dark-theme":"ethical-alabaster"):s.is_mkdocs_builder()&&s.is_rtd_like_theme()?(r="nav.wy-nav-side",e="ethical-rtd ethical-dark-theme"):s.is_rtd_like_theme()?(r="nav.wy-nav-side > div.wy-side-scroll",e="ethical-rtd ethical-dark-theme"):s.is_alabaster_like_theme()&&(r="div.sphinxsidebar > div.sphinxsidebarwrapper",e="ethical-alabaster"),r?((!(a=(n=$("

").appendTo(r)).offset())||a.top-window.scrollY+200>window.innerHeight)&&(s.is_rtd_like_theme()?(r=$("
").insertAfter("footer hr"),e="ethical-rtd",Math.random()<=.25&&(i="stickybox",o="image")):s.is_alabaster_like_theme()&&(r="div.bodywrapper .body",e="ethical-alabaster")),n.remove(),$("
").attr("id","rtd-sidebar").attr("data-ea-publisher","readthedocs").attr("data-ea-type",o).attr("data-ea-manual","true").attr("data-ea-style",i).addClass(e).appendTo(r)):null),(a=document.createElement("script")).src="https://media.ethicalads.io/media/client/beta/ethicalads.min.js",a.type="text/javascript",a.async=!0,a.id="ethicaladsjs",document.getElementsByTagName("head")[0].appendChild(a),$.ajax({url:s.api_host+"/api/v2/sustainability/data/",crossDomain:!0,xhrFields:{withCredentials:!0},dataType:"jsonp",data:{format:"jsonp",project:s.project},success:function(e){t&&!e.ad_free&&(e.keywords&&t.attr("data-ea-keywords",e.keywords.join("|")),e.campaign_types&&t.attr("data-ea-campaign-types",e.campaign_types.join("|")),e.publisher&&t.attr("data-ea-publisher",e.publisher),"undefined"!=typeof ethicalads?ethicalads.load():!s.ad_free&&u()?(h(),p(t)):document.getElementById("ethicaladsjs").addEventListener("load",function(){"undefined"!=typeof ethicalads&ðicalads.load()}))},error:function(){console.error("Error loading Read the Docs user and project information"),!s.ad_free&&u()&&(h(),p(t))}}))}}},{"./constants":12,"./rtd-data":14}],18:[function(e,t,i){t.exports={createDomNode:function(e,t){let i=document.createElement(e);if(t)for(var n of Object.keys(t))i.setAttribute(n,t[n]);return i},domReady:function(e){"complete"===document.readyState||"interactive"===document.readyState?setTimeout(e,1):document.addEventListener("DOMContentLoaded",e)}}},{}],19:[function(e,t,i){const o=e("./rtd-data"),a=e("./utils")["createDomNode"];t.exports={init:function(i){var n,r=o.get();if(!i.is_highest){r=window.location.pathname.replace(r.version,i.slug);let t=a("div",{class:"admonition warning"}),e=a("a",{href:r});e.innerText=i.slug,t.innerHTML='

Note

You are not reading the most recent version of this documentation. '+e.outerHTML+" is the latest version available.

";for(n of["[role=main]","main","div.body","div.document"]){let e=document.querySelector(n);if(null!==e){e.prepend(t);break}}}}}},{"./rtd-data":14,"./utils":18}],20:[function(n,e,t){const r=n("./doc-embed/sponsorship"),o=n("./doc-embed/footer.js"),a=n("./doc-embed/sphinx"),s=n("./doc-embed/search"),i=n("./doc-embed/utils")["domReady"],l=n("./doc-embed/rtd-data");i(function(){var t=function(){o.init(),a.init(),s.init(),r.init()};if(window.jQuery)t();else{console.debug("JQuery not found. Injecting.");var i=l.get();let e=document.createElement("script");e.type="text/javascript",e.src=i.proxied_static_path+"vendor/jquery.js",e.onload=function(){window.$=n("jquery"),window.jQuery=window.$,t()},document.head.appendChild(e)}})},{"./doc-embed/footer.js":13,"./doc-embed/rtd-data":14,"./doc-embed/search":15,"./doc-embed/sphinx":16,"./doc-embed/sponsorship":17,"./doc-embed/utils":18,jquery:"jquery"}]},{},[20]); \ No newline at end of file +!function i(o,a,r){function s(t,e){if(!a[t]){if(!o[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(d)return d(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}n=a[t]={exports:{}},o[t][0].call(n.exports,function(e){return s(o[t][1][e]||e)},n,n.exports,i,o,a,r)}return a[t].exports}for(var d="function"==typeof require&&require,e=0;e
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var t=n(this);(expand=n('')).on("click",function(e){return i.toggleCurrent(t),e.stopPropagation(),!1}),t.prepend(expand)})},reset:function(){var e=encodeURI(window.location.hash)||"#";try{var t,n=$(".wy-menu-vertical"),i=n.find('[href="'+e+'"]');0===i.length&&(t=$('.document [id="'+e.substring(1)+'"]').closest("div.section"),0===(i=n.find('[href="#'+t.attr("id")+'"]')).length&&(i=n.find('[href="#"]'))),0this.docHeight||(this.navBar.scrollTop(n),this.winPosition=e)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},toggleCurrent:function(e){e=e.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:t.exports.ThemeNav,StickyNav:t.exports.ThemeNav});for(var a=0,o=["ms","moz","webkit","o"],r=0;r{if(e.ok)return e.json();throw new Error}).then(t=>{t.show_version_warning&&a.init(t.version_compare);{var n=o.get();let e=document.querySelector(r);if(null!==e)e.innerHTML=t.html;else if(n.is_sphinx_builder()&&n.is_rtd_like_theme()){let e=document.querySelector("div.rst-other-versions");null!==e&&(e.innerHTML=t.html)}else document.body.insertAdjacentHTML("beforeend",t.html);if(t.version_active)t.version_supported;else for(var i of document.getElementsByClassName("rst-current-version"))i.classList.add("rst-out-of-date");return}}).catch(e=>{console.error("Error loading Read the Docs footer")}),{project:t.project,version:t.version,absolute_uri:window.location.href}),t=t.proxied_api_host+"/api/v2/analytics/?"+new URLSearchParams(e).toString();fetch(t,{method:"GET",cache:"no-store"}).then(e=>{if(!e.ok)throw new Error}).catch(e=>{console.error("Error registering page view")})}}},{"./rtd-data":4,"./version-compare":9}],4:[function(e,t,n){var i=e("./constants"),o={is_rtd_like_theme:function(){return 1===document.querySelectorAll("div.rst-other-versions").length||(this.theme===i.THEME_RTD||this.theme===i.THEME_MKDOCS_RTD)},is_alabaster_like_theme:function(){return-1{t.appendChild(e)})}for(c of t.getElementsByTagName("span"))c.className="highlighted";n.appendChild(t),l{if(e.ok)return e.json();throw new Error}).then(e=>{0{i()})}var t,E=o.project,a=o.version,r=o.language||"en";"undefined"!=typeof Search&&E&&a&&(o.features&&o.features.docsearch_disabled?console.log("Server side search is disabled."):(t=Search.query,Search.query_fallback=t,Search.query=e)),s(function(){"undefined"!=typeof Search&&Search.init()})}t.exports={init:function(){var e=i.get();e.is_sphinx_builder()?a(e):console.log("Server side search is disabled.")}}},{"./rtd-data":4,"./utils":8}],6:[function(i,e,t){const o=i("./rtd-data"),a=i("./utils")["domReady"];e.exports={init:function(){var e,t=o.get(),n=document.querySelector("[data-toggle='rst-current-version']");null!=n&&n.addEventListener("click",function(){var e=$("[data-toggle='rst-versions']").hasClass("shift-up")?"was_open":"was_closed";"undefined"!=typeof READTHEDOCS_DATA&&READTHEDOCS_DATA.global_analytics_code&&("undefined"!=typeof gtag?gtag("event","Click",{event_category:"Flyout",event_label:e,send_to:"rtfd"}):"undefined"!=typeof ga?ga("rtfd.send","event","Flyout","Click",e):"undefined"!=typeof _gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Flyout","Click",e]))}),void 0===window.SphinxRtdTheme&&(e=i("./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js").ThemeNav,a(function(){setTimeout(function(){e.navBar||e.enable()},1e3)}),t.is_rtd_like_theme()&&!$("div.wy-side-scroll:first").length&&(console.log("Applying theme sidebar fix..."),n=$("nav.wy-nav-side:first"),t=$("
").addClass("wy-side-scroll"),n.children().detach().appendTo(t),t.prependTo(n),e.navBar=t))}}},{"./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js":1,"./rtd-data":4,"./utils":8}],7:[function(e,t,n){e("./constants");var s,d=e("./rtd-data"),l="[data-ea-publisher]",c="#ethical-ad-placement";function h(){var e=!1;return $("
").attr("id","rtd-detection").attr("class","ethical-rtd").html(" ").appendTo("body"),0===$("#rtd-detection").height()&&(e=!0),$("#rtd-detection").remove(),e}function u(){console.log("---------------------------------------------------------------------------------------"),console.log("Read the Docs hosts documentation for tens of thousands of open source projects."),console.log("We fund our development (we are open source) and operations through advertising."),console.log("We promise to:"),console.log(" - never let advertisers run 3rd party JavaScript"),console.log(" - never sell user data to advertisers or other 3rd parties"),console.log(" - only show advertisements of interest to developers"),console.log("Read more about our approach to advertising here: https://docs.readthedocs.io/en/latest/advertising/ethical-advertising.html"),console.log("%cPlease allow our Ethical Ads or go ad-free:","font-size: 2em"),console.log("https://docs.readthedocs.io/en/latest/advertising/ad-blocking.html"),console.log("--------------------------------------------------------------------------------------")}function p(e){e&&(e=e.attr("class","keep-us-sustainable"),$("

").text("Support Read the Docs!").appendTo(e),$("

").html('Please help keep us sustainable by allowing our Ethical Ads in your ad blocker or go ad-free by subscribing.').appendTo(e),$("

").text("Thank you! ❤️").appendTo(e))}t.exports={init:function(){var t,e,n,i,o,a,r;(s=d.get()).show_promo()&&(o=null,a="readthedocs-sidebar",t=0<$(l).length?($(l).attr("data-ea-publisher","readthedocs"),$(l).attr("data-ea-manual","true"),"image"!==$(l).attr("data-ea-type")&&"text"!==$(l).attr("data-ea-type")&&$(l).attr("data-ea-type","readthedocs-sidebar"),$(l)):(0<$(c).length?(o=c,e=s.is_rtd_like_theme()?"ethical-rtd ethical-dark-theme":"ethical-alabaster"):s.is_mkdocs_builder()&&s.is_rtd_like_theme()?(o="nav.wy-nav-side",e="ethical-rtd ethical-dark-theme"):s.is_rtd_like_theme()?(o="nav.wy-nav-side > div.wy-side-scroll",e="ethical-rtd ethical-dark-theme"):s.is_alabaster_like_theme()&&(o="div.sphinxsidebar > div.sphinxsidebarwrapper",e="ethical-alabaster"),o?((!(r=(i=$("

").appendTo(o)).offset())||r.top-window.scrollY+200>window.innerHeight)&&(s.is_rtd_like_theme()?(o=$("
").insertAfter("footer hr"),e="ethical-rtd",Math.random()<=.25&&(n="stickybox",a="image")):s.is_alabaster_like_theme()&&(o="div.bodywrapper .body",e="ethical-alabaster")),i.remove(),$("
").attr("id","rtd-sidebar").attr("data-ea-publisher","readthedocs").attr("data-ea-type",a).attr("data-ea-manual","true").attr("data-ea-style",n).addClass(e).appendTo(o)):null),(r=document.createElement("script")).src="https://media.ethicalads.io/media/client/beta/ethicalads.min.js",r.type="text/javascript",r.async=!0,r.id="ethicaladsjs",document.getElementsByTagName("head")[0].appendChild(r),$.ajax({url:s.api_host+"/api/v2/sustainability/data/",crossDomain:!0,xhrFields:{withCredentials:!0},dataType:"jsonp",data:{format:"jsonp",project:s.project},success:function(e){t&&!e.ad_free&&(e.keywords&&t.attr("data-ea-keywords",e.keywords.join("|")),e.campaign_types&&t.attr("data-ea-campaign-types",e.campaign_types.join("|")),e.publisher&&t.attr("data-ea-publisher",e.publisher),"undefined"!=typeof ethicalads?ethicalads.load():!s.ad_free&&h()?(u(),p(t)):document.getElementById("ethicaladsjs").addEventListener("load",function(){"undefined"!=typeof ethicalads&ðicalads.load()}))},error:function(){console.error("Error loading Read the Docs user and project information"),!s.ad_free&&h()&&(u(),p(t))}}))}}},{"./constants":2,"./rtd-data":4}],8:[function(e,t,n){t.exports={createDomNode:function(e,t){let n=document.createElement(e);if(t)for(var i of Object.keys(t))n.setAttribute(i,t[i]);return n},domReady:function(e){"complete"===document.readyState||"interactive"===document.readyState?setTimeout(e,1):document.addEventListener("DOMContentLoaded",e)}}},{}],9:[function(e,t,n){const a=e("./rtd-data"),r=e("./utils")["createDomNode"];t.exports={init:function(n){var i,o=a.get();if(!n.is_highest){o=window.location.pathname.replace(o.version,n.slug);let t=r("div",{class:"admonition warning"}),e=r("a",{href:o});e.innerText=n.slug,t.innerHTML='

Note

You are not reading the most recent version of this documentation. '+e.outerHTML+" is the latest version available.

";for(i of["[role=main]","main","div.body","div.document"]){let e=document.querySelector(i);if(null!==e){e.prepend(t);break}}}}}},{"./rtd-data":4,"./utils":8}],10:[function(i,e,t){const o=i("./doc-embed/sponsorship"),a=i("./doc-embed/footer.js"),r=i("./doc-embed/sphinx"),s=i("./doc-embed/search"),n=i("./doc-embed/utils")["domReady"],d=i("./doc-embed/rtd-data");n(function(){var t=function(){a.init(),r.init(),s.init(),o.init()};if(window.jQuery)t();else{console.debug("JQuery not found. Injecting.");var n=d.get();let e=document.createElement("script");e.type="text/javascript",e.src=n.proxied_static_path+"vendor/jquery.js",e.onload=function(){window.$=i("jquery"),window.jQuery=window.$,t()},document.head.appendChild(e)}})},{"./doc-embed/footer.js":3,"./doc-embed/rtd-data":4,"./doc-embed/search":5,"./doc-embed/sphinx":6,"./doc-embed/sponsorship":7,"./doc-embed/utils":8,jquery:"jquery"}]},{},[10]); \ No newline at end of file