<commit_before><!DOCTYPE html>
<html id="library-documentation-top" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="Generator" content="">
<link rel="icon" type="image/x-icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKcAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAqAAAAAAAAAAAAAAAAAAAALIAAAD/AAAA4AAAANwAAADcAAAA3AAAANwAAADcAAAA3AAAANwAAADcAAAA4AAAAP8AAACxAAAAAAAAAKYAAAD/AAAAuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/AAAA/wAAAKkAAAD6AAAAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN8AAAD/AAAA+gAAAMMAAAAAAAAAAgAAAGsAAABrAAAAawAAAGsAAABrAAAAawAAAGsAAABrAAAADAAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAAIsAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAANEAAAAAAAAA2gAAAP8AAAD6AAAAwwAAAAAAAAAAAAAAMgAAADIAAAAyAAAAMgAAADIAAAAyAAAAMgAAADIAAAAFAAAAAAAAANoAAAD/AAAA+gAAAMMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAADwAAAB8AAAAAAAAAGAAAABcAAAAAAAAAH8AAABKAAAAAAAAAAAAAAAAAAAA2gAAAP8AAAD6AAAAwwAAAAAAAADCAAAA/wAAACkAAADqAAAA4QAAAAAAAAD7AAAA/wAAALAAAAAGAAAAAAAAANoAAAD/AAAA+gAAAMMAAAAAAAAAIwAAAP4AAAD/AAAA/wAAAGAAAAAAAAAAAAAAAMkAAAD/AAAAigAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAAAAAAAAIAAAAcAAAABkAAAAAAAAAAAAAAAAAAAAAAAAAEgAAAAAAAAAAAAAA2gAAAP8AAAD7AAAAywAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN4AAAD/AAAAqwAAAP8AAACvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALIAAAD/AAAAsgAAAAAAAAC5AAAA/wAAAMoAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMkAAAD/AAAAvAAAAAAAAAAAAAAAAAAAAKwAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAArQAAAAAAAAAAwAMAAIABAAAf+AAAP/wAAD/8AAAgBAAAP/wAAD/8AAA//AAAJIwAADHEAAA//AAAP/wAAB/4AACAAQAAwAMAAA==">
<link rel="stylesheet" type="text/css" href="libdoc.css" media="all">
<link rel="stylesheet" type="text/css" href="pygments.css" media="all">
<link rel="stylesheet" type="text/css" href="print.css" media="print">
<link rel="stylesheet" type="text/css" href="../common/js_disabled.css" media="all">
<link rel="stylesheet" type="text/css" href="doc_formatting.css" media="all">
<script type="text/javascript" src="../common/storage.js"></script>
<script type="text/javascript" src="../rebot/util.js"></script> <!-- TODO: Should util.js be moved under common? -->
<script type="text/javascript" src="../lib/jquery.min.js"></script>
<script type="text/javascript" src="../lib/jquery.tmpl.min.js"></script>
<script type="text/javascript" src="../lib/jquery.highlight.min.js"></script>
<!-- JS MODEL --><script type="text/javascript" src="../testdata/libdoc.js"></script>
<title></title>
</head>
<body>

<div id="javascript-disabled">
  <h1>Opening library documentation failed</h1>
  <ul>
    <li>Verify that you have <b>JavaScript enabled</b> in your browser.</li>
    <li>Make sure you are using a <b>modern enough browser</b>. If using Internet Explorer, version 11 is required.</li>
    <li>Check are there messages in your browser's <b>JavaScript error log</b>. Please report the problem if you suspect you have encountered a bug.</li>
  </ul>
</div>

<script type="text/javascript">
    // Not using jQuery here for speed and to support ancient browsers.
    document.getElementById('javascript-disabled').style.display = 'none';
    window.addEventListener("hashchange", function() {
      document.getElementsByClassName("hamburger-menu")[0].checked = false;
    }, false);
</script>

<script type="text/javascript">

    $(document).ready(function() {
        parseTemplates();
        document.title = libdoc.name;
        storage.init('libdoc');
        renderTemplate('base', libdoc, $('body'));
        if (libdoc.inits.length) {
            libdoc.typedocs.map(function(type) {
                var index = type.usages.indexOf('__init__');
                if (index != -1) type.usages[index] = 'Importing';
            });
            renderTemplate('importing', libdoc);
        }
        renderTemplate('shortcuts', libdoc);
        renderTemplate('keyword-shortcuts', libdoc);
        renderTemplate('keywords', libdoc);
        renderTemplate('data-types', libdoc);
        renderTemplate('footer', libdoc);
        const params = util.parseQueryString(window.location.search.slice(1));
        let selectedTag = "";
        if ("tag" in params) {
            selectedTag = params["tag"];
            tagSearch(selectedTag, window.location.hash);
        }
        if (libdoc.tags.length) {
          libdoc.selectedTag = selectedTag;
          renderTemplate('tags-shortcuts', libdoc);
        }
        scrollToHash();
        setTimeout(function() {
          document.getElementById("keyword-statistics-header").innerText = '' + libdoc.keywords.length;
          if (storage.get('keyword-wall') === 'open') {
            openKeywordWall();
          }
      }, 0);
        workaroundFirefoxWidthBug();
        createModal();
    });

    function parseTemplates() {
        $('script[type="text/x-jquery-tmpl"]').map(function (idx, elem) {
            $.template(elem.id, elem.text);
        });
    }

    function renderTemplate(name, arguments, container) {
      if (!container) {
          container = $('#' + name + '-container');
          container.empty();
      }
      if (!arguments.search) {
          arguments.search = false;
      }
      $.tmpl(name + '-template', arguments).appendTo(container);
    }

    function scrollToHash() {
        if (window.location.hash) {
            var hash = window.location.hash.substring(1).replace('+', ' ');
            window.location.hash = '';
            window.location.hash = hash;
        }
    }

    function tagSearch(tag, hash) {
      document.getElementsByClassName('search-input')[0].value = '';
      const include = {tags: true, tagsExact: true};
      const url = window.location.pathname + "?tag=" + tag + (hash || "");
      markMatches(tag, include);
      highlightMatches(tag, include);
      history.replaceState && history.replaceState(null, '', url);
      document.getElementById('keyword-shortcuts-container').scrollTop = 0;
    }

    function clearTagSearch() {
      document.getElementsByClassName('search-input')[0].value = '';
      history.replaceState && history.replaceState(null, '', window.location.pathname);
      resetKeywords();
    }

    function closeMenu() {
      document.getElementById('hamburger-menu-input').checked = false;
    }

    function markMatches(pattern, include, givenSearchTime, callback) {
       if (givenSearchTime && givenSearchTime !== searchTime) {
         return;
       }
        let patternRegexp = util.regexpEscape(pattern);
        if (include.tagsExact) {
            patternRegexp = '^' + patternRegexp + '$';
        }
        let regexp = new RegExp(patternRegexp, 'i');
        let test = regexp.test.bind(regexp);
        let result = {};
        let keywordMatchCount = 0;
        result.keywords = util.map(libdoc.keywords, function (kw) {
            kw = $.extend({}, kw);
            kw.hidden =  !(include.name && test(kw.name)) &&
                         !(include.args && test(kw.args)) &&
                          !(include.doc && test($(kw.doc).text())) &&
                          !(include.tags && util.any(util.map(kw.tags, test)));
            if (!kw.hidden)
                keywordMatchCount++;
            return kw;
        });
        renderTemplate('keyword-shortcuts', result);
        renderTemplate('keywords', result);
        if (libdoc.tags.length) {
          libdoc.selectedTag = include.tagsExact ? pattern : "";
          renderTemplate('tags-shortcuts', libdoc);
        }
        document.getElementById("keyword-statistics-header").innerText = keywordMatchCount + ' / ' + result.keywords.length;
        if (keywordMatchCount === 0)
            $('#keywords-container').find('table').empty();
        if (callback) {
          requestAnimationFrame(callback);
        }
    }

    function highlightMatches(string, include, givenSearchTime) {
       if (givenSearchTime && givenSearchTime !== searchTime) {
         return;
       }
        const shortcuts = $('#shortcuts-container').find('.match');
        const keywords = $('#keywords-container').find('.match');
        if (include.name) {
            shortcuts.highlight(string);
            keywords.find('.kw').highlight(string);
        }
        if (include.args) {
            keywords.find('.args').highlight(string);
        }
        if (include.doc) {
            keywords.find('.doc').highlight(string);
        }
        if (include.tags) {
            var matches = keywords.find('.tags').find('a').add(
                    $('#tags-shortcuts-container').find('a'));
            if (include.tagsExact) {
                matches = matches.filter(function (index, tag) {
                    return $(tag).text().toUpperCase() === string.toUpperCase();
                });
            }
            matches.highlight(string);
        }
    }

    function clearSearch() {
      document.getElementsByClassName('search-input')[0].value = '';
      const tagsSelect = document.getElementById('tags-shortcuts-container');
      if (tagsSelect) {
        tagsSelect.selectedIndex = 0;
      }
      resetKeywords();
    }

    let searchTime = 0;

    function searching() {
      searchTime = Date.now();
      const value = document.getElementsByClassName('search-input')[0].value;
      const include = {name: true,
                       args: true,
                       doc: true,
                       tags: true};
      if (value) {
        requestAnimationFrame(function () {
          markMatches(value, include, searchTime,
                  function () {
                    highlightMatches(value, include, searchTime);
                    document.getElementById('keyword-shortcuts-container').scrollTop = 0;
                  }
          );
        });
      } else {
          resetKeywords();
      }
    }

    function toggleShortcuts() {
      const shortcuts = document.getElementsByClassName("shortcuts")[0];
      if (shortcuts.classList.contains("keyword-wall")) {
        closeKeywordWall();
      } else {
        openKeywordWall();
      }
    }

    function openKeywordWall() {
      const shortcuts = document.getElementsByClassName("shortcuts")[0];
      shortcuts.classList.add("keyword-wall");
      storage.set("keyword-wall", 'open');
      const button = document.getElementById("toggle-keyword-shortcuts")
      button.innerText = '-';
    }

    function closeKeywordWall() {
      const shortcuts = document.getElementsByClassName("shortcuts")[0];
      shortcuts.classList.remove("keyword-wall");
      storage.set("keyword-wall", 'close');
      const button = document.getElementById("toggle-keyword-shortcuts")
      button.innerText = '+';
    }

    function resetKeywords() {
        renderTemplate('keyword-shortcuts', libdoc);
        renderTemplate('keywords', libdoc);
        renderTemplate('data-types', libdoc);
        if (libdoc.tags.length) {
            renderTemplate('tags', libdoc);
        }
        document.getElementById("keyword-statistics-header").innerText = ''+libdoc.keywords.length;
        if (libdoc.typedocs.length) {
            document.getElementById("type-statistics-header").innerText = '' + libdoc.typedocs.length;
        }
        history.replaceState && history.replaceState(null, '', location.pathname);
    }

    function createModal() {
        const modalBackground = document.createElement('div');
        modalBackground.id = 'modal-background';
        modalBackground.classList.add('modal-background');
        modalBackground.addEventListener('click', ({ target }) => {
            if (target.id === 'modal-background') hideModal()
        })

        const modal = document.createElement('div');
        modal.id = 'modal';
        modal.classList.add('modal');
        modal.addEventListener('click', ({ target }) => {
            if (target.tagName.toUpperCase() === 'A') hideModal()
        })

        const modalCloseButtonWrapper = document.createElement('div');
        modalCloseButtonWrapper.classList.add('modal-close-button-wrapper');
        const modalCloseButton = document.createElement('button');
        modalCloseButton.innerHTML = 'X';
        modalCloseButton.classList.add('modal-close-button');
        modalCloseButtonWrapper.appendChild(modalCloseButton)
        modalCloseButton.addEventListener('click', () => {
            hideModal()
        })
        modal.appendChild(modalCloseButtonWrapper);

        const modalContent = document.createElement('div');
        modalContent.id = 'modal-content';
        modalContent.classList.add('modal-content');
        modal.appendChild(modalContent);

        modalBackground.appendChild(modal);
        document.body.appendChild(modalBackground);
        document.addEventListener('keydown', ({ key }) => {
            if (key === 'Escape') hideModal()
        })
    }
    function showModal(content) {
        const modalBackground = document.getElementById('modal-background');
        const modal = document.getElementById('modal');
        const modalContent = document.getElementById('modal-content');
        modalBackground.classList.add('visible');
        modal.classList.add('visible');
        modalContent.appendChild(content.cloneNode(true));
        document.body.style.overflow = 'hidden'
    }
    function hideModal() {
        const modalBackground = document.getElementById('modal-background');
        const modal = document.getElementById('modal');
        const modalContent = document.getElementById('modal-content');

        modalBackground.classList.remove('visible');
        modal.classList.remove('visible');
        document.body.style.overflow = 'auto'
        // modal is hidden with a fading transition, timeout prevents premature emptying of modal
        setTimeout(() => {
            modalContent.innerHTML = ''
        }, 200)
    }

    // http://stackoverflow.com/a/18484799
    var delay = (function () {
        var timer = 0;
        return function(callback, ms) {
            clearTimeout(timer);
            timer = setTimeout(callback, ms);
        };
    })();

    function workaroundFirefoxWidthBug() {<commit_msg>Libdoc: Fix workaround for Firefox width bug.<commit_after><!DOCTYPE html>
<html id="library-documentation-top" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="Generator" content="">
<link rel="icon" type="image/x-icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKcAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAqAAAAAAAAAAAAAAAAAAAALIAAAD/AAAA4AAAANwAAADcAAAA3AAAANwAAADcAAAA3AAAANwAAADcAAAA4AAAAP8AAACxAAAAAAAAAKYAAAD/AAAAuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/AAAA/wAAAKkAAAD6AAAAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN8AAAD/AAAA+gAAAMMAAAAAAAAAAgAAAGsAAABrAAAAawAAAGsAAABrAAAAawAAAGsAAABrAAAADAAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAAIsAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAANEAAAAAAAAA2gAAAP8AAAD6AAAAwwAAAAAAAAAAAAAAMgAAADIAAAAyAAAAMgAAADIAAAAyAAAAMgAAADIAAAAFAAAAAAAAANoAAAD/AAAA+gAAAMMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAADwAAAB8AAAAAAAAAGAAAABcAAAAAAAAAH8AAABKAAAAAAAAAAAAAAAAAAAA2gAAAP8AAAD6AAAAwwAAAAAAAADCAAAA/wAAACkAAADqAAAA4QAAAAAAAAD7AAAA/wAAALAAAAAGAAAAAAAAANoAAAD/AAAA+gAAAMMAAAAAAAAAIwAAAP4AAAD/AAAA/wAAAGAAAAAAAAAAAAAAAMkAAAD/AAAAigAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAAAAAAAAIAAAAcAAAABkAAAAAAAAAAAAAAAAAAAAAAAAAEgAAAAAAAAAAAAAA2gAAAP8AAAD7AAAAywAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN4AAAD/AAAAqwAAAP8AAACvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALIAAAD/AAAAsgAAAAAAAAC5AAAA/wAAAMoAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMkAAAD/AAAAvAAAAAAAAAAAAAAAAAAAAKwAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAArQAAAAAAAAAAwAMAAIABAAAf+AAAP/wAAD/8AAAgBAAAP/wAAD/8AAA//AAAJIwAADHEAAA//AAAP/wAAB/4AACAAQAAwAMAAA==">
<link rel="stylesheet" type="text/css" href="libdoc.css" media="all">
<link rel="stylesheet" type="text/css" href="pygments.css" media="all">
<link rel="stylesheet" type="text/css" href="print.css" media="print">
<link rel="stylesheet" type="text/css" href="../common/js_disabled.css" media="all">
<link rel="stylesheet" type="text/css" href="doc_formatting.css" media="all">
<script type="text/javascript" src="../common/storage.js"></script>
<script type="text/javascript" src="../rebot/util.js"></script> <!-- TODO: Should util.js be moved under common? -->
<script type="text/javascript" src="../lib/jquery.min.js"></script>
<script type="text/javascript" src="../lib/jquery.tmpl.min.js"></script>
<script type="text/javascript" src="../lib/jquery.highlight.min.js"></script>
<!-- JS MODEL --><script type="text/javascript" src="../testdata/libdoc.js"></script>
<title></title>
</head>
<body>

<div id="javascript-disabled">
  <h1>Opening library documentation failed</h1>
  <ul>
    <li>Verify that you have <b>JavaScript enabled</b> in your browser.</li>
    <li>Make sure you are using a <b>modern enough browser</b>. If using Internet Explorer, version 11 is required.</li>
    <li>Check are there messages in your browser's <b>JavaScript error log</b>. Please report the problem if you suspect you have encountered a bug.</li>
  </ul>
</div>

<script type="text/javascript">
    // Not using jQuery here for speed and to support ancient browsers.
    document.getElementById('javascript-disabled').style.display = 'none';
    window.addEventListener("hashchange", function() {
      document.getElementsByClassName("hamburger-menu")[0].checked = false;
    }, false);
</script>

<script type="text/javascript">

    $(document).ready(function() {
        parseTemplates();
        document.title = libdoc.name;
        storage.init('libdoc');
        renderTemplate('base', libdoc, $('body'));
        if (libdoc.inits.length) {
            libdoc.typedocs.map(function(type) {
                var index = type.usages.indexOf('__init__');
                if (index != -1) type.usages[index] = 'Importing';
            });
            renderTemplate('importing', libdoc);
        }
        renderTemplate('shortcuts', libdoc);
        renderTemplate('keyword-shortcuts', libdoc);
        renderTemplate('keywords', libdoc);
        renderTemplate('data-types', libdoc);
        renderTemplate('footer', libdoc);
        const params = util.parseQueryString(window.location.search.slice(1));
        let selectedTag = "";
        if ("tag" in params) {
            selectedTag = params["tag"];
            tagSearch(selectedTag, window.location.hash);
        }
        if (libdoc.tags.length) {
          libdoc.selectedTag = selectedTag;
          renderTemplate('tags-shortcuts', libdoc);
        }
        scrollToHash();
        setTimeout(function() {
          document.getElementById("keyword-statistics-header").innerText = '' + libdoc.keywords.length;
          if (storage.get('keyword-wall') === 'open') {
            openKeywordWall();
          }
      }, 0);
        createModal();
    });

    function parseTemplates() {
        $('script[type="text/x-jquery-tmpl"]').map(function (idx, elem) {
            $.template(elem.id, elem.text);
        });
    }

    function renderTemplate(name, arguments, container) {
      if (!container) {
          container = $('#' + name + '-container');
          container.empty();
      }
      if (!arguments.search) {
          arguments.search = false;
      }
      $.tmpl(name + '-template', arguments).appendTo(container);
    }

    function scrollToHash() {
        if (window.location.hash) {
            var hash = window.location.hash.substring(1).replace('+', ' ');
            window.location.hash = '';
            window.location.hash = hash;
        }
    }

    function tagSearch(tag, hash) {
      document.getElementsByClassName('search-input')[0].value = '';
      const include = {tags: true, tagsExact: true};
      const url = window.location.pathname + "?tag=" + tag + (hash || "");
      markMatches(tag, include);
      highlightMatches(tag, include);
      history.replaceState && history.replaceState(null, '', url);
      document.getElementById('keyword-shortcuts-container').scrollTop = 0;
    }

    function clearTagSearch() {
      document.getElementsByClassName('search-input')[0].value = '';
      history.replaceState && history.replaceState(null, '', window.location.pathname);
      resetKeywords();
    }

    function closeMenu() {
      document.getElementById('hamburger-menu-input').checked = false;
    }

    function markMatches(pattern, include, givenSearchTime, callback) {
       if (givenSearchTime && givenSearchTime !== searchTime) {
         return;
       }
        let patternRegexp = util.regexpEscape(pattern);
        if (include.tagsExact) {
            patternRegexp = '^' + patternRegexp + '$';
        }
        let regexp = new RegExp(patternRegexp, 'i');
        let test = regexp.test.bind(regexp);
        let result = {};
        let keywordMatchCount = 0;
        result.keywords = util.map(libdoc.keywords, function (kw) {
            kw = $.extend({}, kw);
            kw.hidden =  !(include.name && test(kw.name)) &&
                         !(include.args && test(kw.args)) &&
                          !(include.doc && test($(kw.doc).text())) &&
                          !(include.tags && util.any(util.map(kw.tags, test)));
            if (!kw.hidden)
                keywordMatchCount++;
            return kw;
        });
        renderTemplate('keyword-shortcuts', result);
        renderTemplate('keywords', result);
        if (libdoc.tags.length) {
          libdoc.selectedTag = include.tagsExact ? pattern : "";
          renderTemplate('tags-shortcuts', libdoc);
        }
        document.getElementById("keyword-statistics-header").innerText = keywordMatchCount + ' / ' + result.keywords.length;
        if (keywordMatchCount === 0)
            $('#keywords-container').find('table').empty();
        if (callback) {
          requestAnimationFrame(callback);
        }
    }

    function highlightMatches(string, include, givenSearchTime) {
       if (givenSearchTime && givenSearchTime !== searchTime) {
         return;
       }
        const shortcuts = $('#shortcuts-container').find('.match');
        const keywords = $('#keywords-container').find('.match');
        if (include.name) {
            shortcuts.highlight(string);
            keywords.find('.kw').highlight(string);
        }
        if (include.args) {
            keywords.find('.args').highlight(string);
        }
        if (include.doc) {
            keywords.find('.doc').highlight(string);
        }
        if (include.tags) {
            var matches = keywords.find('.tags').find('a').add(
                    $('#tags-shortcuts-container').find('a'));
            if (include.tagsExact) {
                matches = matches.filter(function (index, tag) {
                    return $(tag).text().toUpperCase() === string.toUpperCase();
                });
            }
            matches.highlight(string);
        }
    }

    function clearSearch() {
      document.getElementsByClassName('search-input')[0].value = '';
      const tagsSelect = document.getElementById('tags-shortcuts-container');
      if (tagsSelect) {
        tagsSelect.selectedIndex = 0;
      }
      resetKeywords();
    }

    let searchTime = 0;

    function searching() {
      searchTime = Date.now();
      const value = document.getElementsByClassName('search-input')[0].value;
      const include = {name: true,
                       args: true,
                       doc: true,
                       tags: true};
      if (value) {
        requestAnimationFrame(function () {
          markMatches(value, include, searchTime,
                  function () {
                    highlightMatches(value, include, searchTime);
                    document.getElementById('keyword-shortcuts-container').scrollTop = 0;
                  }
          );
        });
      } else {
          resetKeywords();
      }
    }

    function toggleShortcuts() {
      const shortcuts = document.getElementsByClassName("shortcuts")[0];
      if (shortcuts.classList.contains("keyword-wall")) {
        closeKeywordWall();
      } else {
        openKeywordWall();
      }
    }

    function openKeywordWall() {
      const shortcuts = document.getElementsByClassName("shortcuts")[0];
      shortcuts.classList.add("keyword-wall");
      storage.set("keyword-wall", 'open');
      const button = document.getElementById("toggle-keyword-shortcuts")
      button.innerText = '-';
    }

    function closeKeywordWall() {
      const shortcuts = document.getElementsByClassName("shortcuts")[0];
      shortcuts.classList.remove("keyword-wall");
      storage.set("keyword-wall", 'close');
      const button = document.getElementById("toggle-keyword-shortcuts")
      button.innerText = '+';
    }

    function resetKeywords() {
        renderTemplate('keyword-shortcuts', libdoc);
        renderTemplate('keywords', libdoc);
        renderTemplate('data-types', libdoc);
        if (libdoc.tags.length) {
            renderTemplate('tags', libdoc);
        }
        document.getElementById("keyword-statistics-header").innerText = ''+libdoc.keywords.length;
        if (libdoc.typedocs.length) {
            document.getElementById("type-statistics-header").innerText = '' + libdoc.typedocs.length;
        }
        history.replaceState && history.replaceState(null, '', location.pathname);
    }

    function createModal() {
        const modalBackground = document.createElement('div');
        modalBackground.id = 'modal-background';
        modalBackground.classList.add('modal-background');
        modalBackground.addEventListener('click', ({ target }) => {
            if (target.id === 'modal-background') hideModal()
        })

        const modal = document.createElement('div');
        modal.id = 'modal';
        modal.classList.add('modal');
        modal.addEventListener('click', ({ target }) => {
            if (target.tagName.toUpperCase() === 'A') hideModal()
        })

        const modalCloseButtonWrapper = document.createElement('div');
        modalCloseButtonWrapper.classList.add('modal-close-button-wrapper');
        const modalCloseButton = document.createElement('button');
        modalCloseButton.innerHTML = 'X';
        modalCloseButton.classList.add('modal-close-button');
        modalCloseButtonWrapper.appendChild(modalCloseButton)
        modalCloseButton.addEventListener('click', () => {
            hideModal()
        })
        modal.appendChild(modalCloseButtonWrapper);

        const modalContent = document.createElement('div');
        modalContent.id = 'modal-content';
        modalContent.classList.add('modal-content');
        modal.appendChild(modalContent);

        modalBackground.appendChild(modal);
        document.body.appendChild(modalBackground);
        document.addEventListener('keydown', ({ key }) => {
            if (key === 'Escape') hideModal()
        })
    }
    function showModal(content) {
        const modalBackground = document.getElementById('modal-background');
        const modal = document.getElementById('modal');
        const modalContent = document.getElementById('modal-content');
        modalBackground.classList.add('visible');
        modal.classList.add('visible');
        modalContent.appendChild(content.cloneNode(true));
        document.body.style.overflow = 'hidden';
        workaroundFirefoxWidthBug();
    }
    function hideModal() {
        const modalBackground = document.getElementById('modal-background');
        const modal = document.getElementById('modal');
        const modalContent = document.getElementById('modal-content');

        modalBackground.classList.remove('visible');
        modal.classList.remove('visible');
        document.body.style.overflow = 'auto';
        // modal is hidden with a fading transition, timeout prevents premature emptying of modal
        setTimeout(() => {
            modalContent.innerHTML = '';
        }, 200);
    }

    // http://stackoverflow.com/a/18484799
    var delay = (function () {
        var timer = 0;
        return function(callback, ms) {
            clearTimeout(timer);
            timer = setTimeout(callback, ms);
        };
    })();

    function workaroundFirefoxWidthBug() {
{'fraction_non_alphanumeric': 0.13792629262926293, 'fraction_numerical': 0.005294279427942794, 'mean_word_length': 2.966321243523316, 'pattern_counts': {'":': 0, '<': 111, '<?xml version=': 0, '>': 121, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 60, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5699310', 'n_tokens_mistral': 8323, 'n_tokens_neox': 8014, 'n_words': 1266}