<div id="bin-search-wrapper">
    <ul id="bin-search-filters" class="function-list">
        {% for function_pair in site.data.functions %}
        {% assign function_id = function_pair[0] %}
        {% assign function = function_pair[1] %}
        <li><a href="#+{{ function.label | downcase }}" data-title="{{ function.description | replace: '\n', ' ' }}">{{ function.label }}</a></li>
        {% endfor %}
    </ul>

    <input id="bin-search" type="text" placeholder="Search among {{ site.gtfobins | size }} binaries: <binary> +<function> ..."/>
</div>

<div id="bin-table-wrapper">
    <table id="bin-table">
        <thead>
            <tr>
                <th>Binary</th>
                <th>Functions</th>
            </tr>
        </thead>
        <tbody>
            {% for file in site.gtfobins %}
            <tr>
                <td><a href="{{ file.url }}" class="bin-name">{% include get_bin_name path=file.path %}</a></td>
                <td>{% include function_list.html bin=file %}</td>
            </tr>
            {% endfor %}
        </tbody>
        <tfoot>
            <tr><td id="search-message" colspan="2">No binary matches...</td></tr>
        </tfoot>
    </table>
</div>

<script>
 function filter(query) {
     var queryArray = query.toLowerCase().trim().split(/ *\+/);
     var binPattern = queryArray[0];
     var functionPatterns = queryArray.splice(1);

     // filter rows
     var noResults = true;
     document.querySelectorAll('#bin-table tbody tr').forEach(function (row) {
         var show = true;

         var binName = row.children[0].firstElementChild.innerText.toLowerCase();
         if (binName.indexOf(binPattern) === -1) {
             show = false;
         }

         if (show) {
             var functionElems = Array.from(row.children[1].firstElementChild.children);
             functionElems.forEach((item) => {
                 item.className = '';
             });
             functionPatterns.forEach((pattern) => {
                 // skip empty filters
                 if (!pattern) {
                     return;
                 }
                 // check against the pattern
                 var noMatches = true;
                 functionElems.forEach((item) => {
                     if (item.innerText.toLowerCase().startsWith(pattern.toLowerCase())) {
                         item.className = 'match';
                         noMatches = false;
                     }
                 });
                 // no function satisfies the pattern
                 if (noMatches) {
                     show = false;
                 }
             });
         }

         if (show) {
             row.style.display = '';
             noResults = false;
         } else {
             row.style.display = 'none';
         }
     });

     // update the search message visibility
     var searchMessage = document.getElementById('search-message');
     searchMessage.style.display = noResults ? 'table-cell' : 'none';
 }

 function applyFilter() {
     // filter on load according to the URL
     var searchBox = document.getElementById('bin-search');
     var query = decodeURIComponent(location.hash.slice(1));
     filter(query);
     if (query) {
         searchBox.value = query;
     }
 }

 function setup() {
     var searchBox = document.getElementById('bin-search');

     // ensure height during filtering
     var binTableWrapper = document.getElementById('bin-table-wrapper');
     binTableWrapper.style.height = binTableWrapper.clientHeight + 'px';

     // handle user input
     searchBox.addEventListener('input', function () {
         var query = searchBox.value;
         history.replaceState(null, null, encodeURI('#' + query));
         applyFilter();
     });

     // handle shortcuts
     addEventListener('keydown', function (event) {
         // focus search box on valid keydown
         if (event.key.toLowerCase().match(/^[+a-z]$/) &&
             !(event.ctrlKey || event.altKey || event.metaKey)) {
             searchBox.focus();
             searchBox.parentElement.scrollIntoView();
         }
         // clear filter on escape
         else if (event.key === 'Escape') {
             location.hash = searchBox.value = '';
             searchBox.focus();
             searchBox.parentElement.scrollIntoView();
         }
     });

     // handle URL changes
     window.onhashchange = applyFilter;

     // trigger filter on page load
     applyFilter();
 }

 setup();
</script>