Skip to content

DigitalA11Y

Your Accessibility Partner

  • Home
  • ServicesExpand
    • WCAG Audit Services
    • VPAT/ACR Services
    • Accessibility Consulting
    • PDF Remediation
    • Accessibility Trainings
    • Website Remediation
    • Design Audit
  • Free ToolsExpand
    • Accessibility Checker
    • A11Y Cost Calculator
    • A11Y Bookmarklets
    • Color Contrast Extension
    • WCAG Contrast Checker
  • ResourcesExpand
    • A11Y Articles
    • WCAG Primer
    • ARIA Cheatsheet
    • A11Y Tools
    • A11Y Patterns
    • A11Y Cheatsheets
  • Contact
Search
DigitalA11Y
Your Accessibility Partner
Search

Autocomplete with Radio Buttons

Favorite hobby suggestions
Provides auto-suggestions when entering text

Code

  • HTML
  • CSS
  • JavaScript
<button href="#" id="before">Focusable element before</button>
<form>
  <div data-adg-autocomplete="">
    <div class="control">
      <label for="favorite_hobby_filter">Favorite hobby </label><input aria-describedby="favorite_hobby_filter_help" id="favorite_hobby_filter" type="text" />
      <fieldset hidden="">
        <legend>Favorite hobby suggestions</legend>
        <div class="control">
          <input id="favorite_hobby_hiking" name="hobby" type="radio" /><label for="favorite_hobby_hiking">Hiking</label>
        </div>
        <div class="control">
          <input id="favorite_hobby_dancing" name="hobby" type="radio" /><label for="favorite_hobby_dancing">Dancing</label>
        </div>
        <div class="control">
          <input id="favorite_hobby_gardening" name="hobby" type="radio" /><label for="favorite_hobby_gardening">Gardening</label>
        </div>
        <div class="control">
          <input id="favorite_hobby_meditation" name="hobby" type="radio" /><label for="favorite_hobby_meditation">Meditation</label>
        </div>
        <div class="control">
          <input id="favorite_hobby_gaming" name="hobby" type="radio" /><label for="favorite_hobby_gaming">Gaming</label>
        </div>
      </fieldset>
      <div class="description" id="favorite_hobby_filter_help">
        Provides auto-suggestions when entering text
      </div>
    </div>
  </div>
</form>
<button href="#" id="after">Focusable element after</button>
@charset "UTF-8";
.adg-visually-hidden {
  position: absolute;
  white-space: nowrap;
  width: 1px;
  height: 1px;
  overflow: hidden;
  border: 0;
  padding: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  margin: -1px;
}

[data-adg-autocomplete-options] {
  position: absolute;
  z-index: 1;
  background-color: #fff;
  border: 1px solid;
  padding: 5px 0;
}

[data-adg-autocomplete-option] {
  display: block;
}

[data-adg-autocomplete-option]:hover,
[data-adg-autocomplete-option-selected] {
  cursor: pointer;
  outline: 1px solid;
}

[data-adg-autocomplete-alerts] p {
  margin: 0;
}
[data-adg-autocomplete-alerts] kbd::before {
  content: "«";
}
[data-adg-autocomplete-alerts] kbd::after {
  content: "»";
}

.control {
  margin: 6px 0;
}

input[type=text] {
  width: 140px;
}

label {
  display: inline-block;
  width: 120px;
  vertical-align: top;
}

.description {
  margin-left: 120px;
}

fieldset {
  margin: -1px 0 0 120px;
}
fieldset .control {
  margin: 0;
}
fieldset label {
  min-width: 144px;
}
(function() {
  this.Adg = {};

  Adg.Base = (function() {
    var config, uniqueIdCount;

    class Base {
      
        // Constructor. Should not be overridden; use @init() instead.

      // - Arg1: The DOM element on which the script should be applied (will be saved as @$el)
      // - Arg2: An optional hash of options which will be merged into the global default config
      constructor(el, options = {}) {
        var key, val;
        this.$el = $(el);
        this.config = config;
        for (key in options) {
          val = options[key];
          this.config[key] = val;
        }
        this.init();
      }

      // Dummy, must be overridden in inheriting classes.
      init() {
        return this.throwMessageAndPrintObjectsToConsole('Classes extending App must implement method init()!');
      }

      // Prints the given message to the console if config['debug'] is true.
      debugMessage(message) {
        if (this.config.debugMessage) {
          return console.log(`Adg debug: ${message}`);
        }
      }

      // Executes the given selector on @$el and returns the element. Makes sure exactly one element exists.
      findOne(selector) {
        var result;
        result = this.$el.find(selector);
        switch (result.length) {
          case 0:
            return this.throwMessageAndPrintObjectsToConsole(`No object found for ${selector}!`, {
              result: result
            });
          case 1:
            return $(result.first());
          default:
            return this.throwMessageAndPrintObjectsToConsole(`More than one object found for ${selector}!`, {
              result: result
            });
        }
      }

      name() {
        return `adg-${this.constructor.name.toLowerCase()}`;
      }

      addAdgDataAttribute($target, name, value = '') {
        return $target.attr(this.adgDataAttributeName(name), value);
      }

      removeAdgDataAttribute($target, name) {
        return $target.removeAttr(this.adgDataAttributeName(name));
      }

      adgDataAttributeName(name = null) {
        var result;
        result = `data-${this.name()}`;
        if (name) {
          result += `-${name}`;
        }
        return result;
      }

      uniqueId(name) {
        return [this.name(), name, uniqueIdCount++].join('-');
      }

      labelOfInput($inputs) {
        return $inputs.map((i, input) => {
          var $input, $label, id;
          $input = $(input);
          id = $input.attr('id');
          $label = this.findOne(`label[for='${id}']`)[0];
          if ($label.length === 0) {
            $label = $input.closest('label');
            if ($label.length === 0) {
              this.throwMessageAndPrintObjectsToConsole("No corresponding input found for input!", {
                input: $input
              });
            }
          }
          return $label;
        });
      }

      show($el) {
        $el.removeAttr('hidden');
        return $el.show();
      }

      // TODO Would be cool to renounce CSS and solely use the hidden attribute. But jQuery's :visible doesn't seem to work with it!?
      // @throwMessageAndPrintObjectsToConsole("Element is still hidden, although hidden attribute was removed! Make sure there's no CSS like display:none or visibility:hidden left on it!", element: $el) if $el.is(':hidden')
      hide($el) {
        $el.attr('hidden', '');
        return $el.hide();
      }

      throwMessageAndPrintObjectsToConsole(message, elements = {}) {
        console.log(elements);
        throw message;
      }

      text(text, options = {}) {
        var key, value;
        text = this.config[`${text}Text`];
        for (key in options) {
          value = options[key];
          text = text.replace(`[${key}]`, value);
        }
        return text;
      }

    };

    uniqueIdCount = 1;

    config = {
      debugMessage: false,
      hiddenCssClass: 'adg-visually-hidden'
    };

    return Base;

  }).call(this);

  Adg.Autocomplete = (function() {
    var config;

    // Tested in JAWS+IE/FF, NVDA+FF

    // Known issues:
    // - JAWS leaves the input when using up/down without entering something (I guess this is due to screen layout and can be considered intended)
    // - Alert not perceivable upon opening options using up/down
    //     - Possible solution 1: always show options count when filter focused?
    //     - Possible solution 2: wait a moment before adding the alert?
    // - VoiceOver/iOS announces radio buttons as disabled?!
    // - iOS doesn't select all text when option was chosen

    // In general: alerts seem to be most robust in all relevant browsers, but aren't polite. Maybe we'll find a better mechanism to serve browsers individually?
    class Autocomplete extends Adg.Base {
      init() {
        var jsonOptions, key, val;
// Merge config into existing one (not nice, see https://stackoverflow.com/questions/47721699/)
        for (key in config) {
          val = config[key];
          this.config[key] = val;
        }
        jsonOptions = this.$el.attr(this.adgDataAttributeName());
        if (jsonOptions) {
          for (key in jsonOptions) {
            val = jsonOptions[key];
            this.config[key] = val;
          }
        }
        this.debugMessage('start');
        this.initFilter();
        this.initOptions();
        this.initAlerts();
        this.applyCheckedOptionToFilter();
        this.announceOptionsNumber('');
        return this.attachEvents();
      }

      initFilter() {
        this.$filter = this.findOne('input[type="text"]');
        this.addAdgDataAttribute(this.$filter, 'filter');
        this.$filter.attr('autocomplete', 'off');
        return this.$filter.attr('aria-expanded', 'false');
      }

      initOptions() {
        this.$optionsContainer = this.findOne(this.config.optionsContainer);
        this.addAdgDataAttribute(this.$optionsContainer, 'options');
        this.$optionsContainerLabel = this.findOne(this.config.optionsContainerLabel);
        this.$optionsContainerLabel.addClass(this.config.hiddenCssClass);
        this.$options = this.$optionsContainer.find('input[type="radio"]');
        this.addAdgDataAttribute(this.labelOfInput(this.$options), 'option');
        return this.$options.addClass(this.config.hiddenCssClass);
      }

      initAlerts() {
        this.$alertsContainer = $(`<div id='${this.uniqueId(this.config.alertsContainerId)}'></div>`);
        this.$optionsContainerLabel.after(this.$alertsContainer);
        this.$filter.attr('aria-describedby', [this.$filter.attr('aria-describedby'), this.$alertsContainer.attr('id')].join(' ').trim());
        return this.addAdgDataAttribute(this.$alertsContainer, 'alerts');
      }

      attachEvents() {
        this.attachClickEventToFilter();
        this.attachChangeEventToFilter();
        this.attachEscapeKeyToFilter();
        this.attachEnterKeyToFilter();
        this.attachTabKeyToFilter();
        this.attachUpDownKeysToFilter();
        this.attachChangeEventToOptions();
        return this.attachClickEventToOptions();
      }

      attachClickEventToFilter() {
        return this.$filter.click(() => {
          this.debugMessage('click filter');
          if (this.$optionsContainer.is(':visible')) {
            return this.hideOptions();
          } else {
            return this.showOptions();
          }
        });
      }

      attachEscapeKeyToFilter() {
        return this.$filter.keydown((e) => {
          if (e.which === 27) {
            if (this.$optionsContainer.is(':visible')) {
              this.applyCheckedOptionToFilterAndResetOptions();
              return e.preventDefault();
            } else if (this.$options.is(':checked')) {
              this.$options.prop('checked', false);
              this.applyCheckedOptionToFilterAndResetOptions();
              return e.preventDefault(); // Needed for automatic testing only
            } else {
              return $('body').append('<p>Esc passed on.</p>');
            }
          }
        });
      }

      attachEnterKeyToFilter() {
        return this.$filter.keydown((e) => {
          if (e.which === 13) {
            this.debugMessage('enter');
            if (this.$optionsContainer.is(':visible')) {
              this.applyCheckedOptionToFilterAndResetOptions();
              return e.preventDefault(); // Needed for automatic testing only
            } else {
              return $('body').append('<p>Enter passed on.</p>');
            }
          }
        });
      }

      attachTabKeyToFilter() {
        return this.$filter.keydown((e) => {
          if (e.which === 9) {
            this.debugMessage('tab');
            if (this.$optionsContainer.is(':visible')) {
              return this.applyCheckedOptionToFilterAndResetOptions();
            }
          }
        });
      }

      attachUpDownKeysToFilter() {
        return this.$filter.keydown((e) => {
          if (e.which === 38 || e.which === 40) {
            if (this.$optionsContainer.is(':visible')) {
              if (e.which === 38) {
                this.moveSelection('up');
              } else {
                this.moveSelection('down');
              }
            } else {
              this.showOptions();
            }
            return e.preventDefault(); // TODO: Test!
          }
        });
      }

      showOptions() {
        this.debugMessage('(show options)');
        this.show(this.$optionsContainer);
        return this.$filter.attr('aria-expanded', 'true');
      }

      hideOptions() {
        this.debugMessage('(hide options)');
        this.hide(this.$optionsContainer);
        return this.$filter.attr('aria-expanded', 'false');
      }

      moveSelection(direction) {
        var $upcomingOption, $visibleOptions, currentIndex, maxIndex, upcomingIndex;
        $visibleOptions = this.$options.filter(':visible');
        maxIndex = $visibleOptions.length - 1;
        currentIndex = $visibleOptions.index($visibleOptions.parent().find(':checked')); // TODO: is parent() good here?!
        upcomingIndex = direction === 'up' ? currentIndex <= 0 ? maxIndex : currentIndex - 1 : currentIndex === maxIndex ? 0 : currentIndex + 1;
        $upcomingOption = $($visibleOptions[upcomingIndex]);
        return $upcomingOption.prop('checked', true).trigger('change');
      }

      attachChangeEventToOptions() {
        return this.$options.change((e) => {
          this.debugMessage('option change');
          this.applyCheckedOptionToFilter();
          return this.$filter.focus().select();
        });
      }

      applyCheckedOptionToFilterAndResetOptions() {
        this.applyCheckedOptionToFilter();
        this.hideOptions();
        return this.filterOptions();
      }

      applyCheckedOptionToFilter() {
        var $checkedOption, $checkedOptionLabel, $previouslyCheckedOptionLabel;
        this.debugMessage('(apply option to filter)');
        $previouslyCheckedOptionLabel = $(`[${this.adgDataAttributeName('option-selected')}]`);
        if ($previouslyCheckedOptionLabel.length === 1) {
          this.removeAdgDataAttribute($previouslyCheckedOptionLabel, 'option-selected');
        }
        $checkedOption = this.$options.filter(':checked');
        if ($checkedOption.length === 1) {
          $checkedOptionLabel = this.labelOfInput($checkedOption);
          this.$filter.val($.trim($checkedOptionLabel.text()));
          return this.addAdgDataAttribute($checkedOptionLabel, 'option-selected');
        } else {
          return this.$filter.val('');
        }
      }

      attachClickEventToOptions() {
        return this.$options.click((e) => {
          this.debugMessage('click option');
          return this.hideOptions();
        });
      }

      attachChangeEventToFilter() {
        return this.$filter.on('input propertychange paste', (e) => {
          this.debugMessage('(filter changed)');
          this.filterOptions(e.target.value);
          return this.showOptions();
        });
      }

      filterOptions(filter = '') {
        var fuzzyFilter, visibleNumber;
        fuzzyFilter = this.fuzzifyFilter(filter);
        visibleNumber = 0;
        this.$options.each((i, el) => {
          var $option, $optionContainer, regex;
          $option = $(el);
          $optionContainer = $option.parent();
          regex = new RegExp(fuzzyFilter, 'i');
          if (regex.test($optionContainer.text())) {
            visibleNumber++;
            return this.show($optionContainer);
          } else {
            return this.hide($optionContainer);
          }
        });
        return this.announceOptionsNumber(filter, visibleNumber);
      }

      announceOptionsNumber(filter = this.$filter.val(), number = this.$options.length) {
        var message;
        this.$alertsContainer.find('p').remove(); // Remove previous alerts (I'm not sure whether this is the best solution, maybe hiding them would be more robust?)
        message = filter === '' ? this.text('numberInTotal', {
          number: number
        }) : this.text('numberFiltered', {
          number: number,
          total: this.$options.length,
          filter: `<kbd>${filter}</kbd>`
        });
        return this.$alertsContainer.append(`<p role='alert'>${message}</p>`);
      }

      fuzzifyFilter(filter) {
        var escapedCharacter, fuzzifiedFilter, i;
        i = 0;
        fuzzifiedFilter = '';
        while (i < filter.length) {
          escapedCharacter = filter.charAt(i).replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); // See https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
          fuzzifiedFilter += `${escapedCharacter}.*?`;
          i++;
        }
        return fuzzifiedFilter;
      }

    };

    config = {
      optionsContainer: 'fieldset',
      optionsContainerLabel: 'legend',
      alertsContainerId: 'alerts',
      numberInTotalText: '[number] options in total',
      numberFilteredText: '[number] of [total] options for [filter]'
    };

    return Autocomplete;

  }).call(this);

  $(document).ready(function() {
    return $('[data-adg-autocomplete]').each(function() {
      return new Adg.Autocomplete(this);
    });
  });

}).call(this);

//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiPGFub255bW91cz4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7RUFBQSxJQUFDLENBQUEsR0FBRCxHQUFPLENBQUE7O0VBRUQsR0FBRyxDQUFDOzs7SUFBVixNQUFBLEtBQUEsQ0FBQTs7Ozs7O01BV0UsV0FBYSxDQUFDLEVBQUQsRUFBSyxVQUFVLENBQUEsQ0FBZixDQUFBO0FBQ2YsWUFBQSxHQUFBLEVBQUE7UUFBSSxJQUFDLENBQUEsR0FBRCxHQUFPLENBQUEsQ0FBRSxFQUFGO1FBRVAsSUFBQyxDQUFBLE1BQUQsR0FBVTtRQUNWLEtBQUEsY0FBQTs7VUFDRSxJQUFDLENBQUEsTUFBTSxDQUFDLEdBQUQsQ0FBUCxHQUFlO1FBRGpCO1FBR0EsSUFBQyxDQUFBLElBQUQsQ0FBQTtNQVBXLENBVmY7OztNQW9CRSxJQUFNLENBQUEsQ0FBQTtlQUNKLElBQUMsQ0FBQSxvQ0FBRCxDQUFzQyxxREFBdEM7TUFESSxDQXBCUjs7O01Bd0JFLFlBQWMsQ0FBQyxPQUFELENBQUE7UUFDWixJQUF1QyxJQUFDLENBQUEsTUFBTSxDQUFDLFlBQS9DO2lCQUFBLE9BQU8sQ0FBQyxHQUFSLENBQVksQ0FBQSxXQUFBLENBQUEsQ0FBYyxPQUFkLENBQUEsQ0FBWixFQUFBOztNQURZLENBeEJoQjs7O01BNEJFLE9BQVMsQ0FBQyxRQUFELENBQUE7QUFDWCxZQUFBO1FBQUksTUFBQSxHQUFTLElBQUMsQ0FBQSxHQUFHLENBQUMsSUFBTCxDQUFVLFFBQVY7QUFDVCxnQkFBTyxNQUFNLENBQUMsTUFBZDtBQUFBLGVBQ08sQ0FEUDttQkFDYyxJQUFDLENBQUEsb0NBQUQsQ0FBc0MsQ0FBQSxvQkFBQSxDQUFBLENBQXVCLFFBQXZCLENBQUEsQ0FBQSxDQUF0QyxFQUEwRTtjQUFBLE1BQUEsRUFBUTtZQUFSLENBQTFFO0FBRGQsZUFFTyxDQUZQO21CQUVjLENBQUEsQ0FBRSxNQUFNLENBQUMsS0FBUCxDQUFBLENBQUY7QUFGZDtt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LENBQXlCLHFDQUF6QixFQUFnRSxNQUFoRSxFQUF6QjtVQUNNLGVBQUEsSUFBbUIsQ0FBQSxDQUFBLENBQUcsZ0JBQUgsQ0FBQSxHQUFBO1VBQ25CLENBQUE7UUFIRjtlQUtBO01BUmE7O0lBak5qQjs7SUFDRSxNQUFBLEdBQ0U7TUFBQSxnQkFBQSxFQUF1QixVQUF2QjtNQUNBLHFCQUFBLEVBQXVCLFFBRHZCO01BRUEsaUJBQUEsRUFBdUIsUUFGdkI7TUFHQSxpQkFBQSxFQUF1QiwyQkFIdkI7TUFJQSxrQkFBQSxFQUF1QjtJQUp2Qjs7Ozs7O0VBeU5KLENBQUEsQ0FBRSxRQUFGLENBQVcsQ0FBQyxLQUFaLENBQWtCLFFBQUEsQ0FBQSxDQUFBO1dBQ2hCLENBQUEsQ0FBRSx5QkFBRixDQUE0QixDQUFDLElBQTdCLENBQWtDLFFBQUEsQ0FBQSxDQUFBO2FBQ2hDLElBQUksR0FBRyxDQUFDLFlBQVIsQ0FBcUIsSUFBckI7SUFEZ0MsQ0FBbEM7RUFEZ0IsQ0FBbEI7QUFqVUEiLCJzb3VyY2VzQ29udGVudCI6WyJAQWRnID0ge31cblxuY2xhc3MgQWRnLkJhc2VcbiAgdW5pcXVlSWRDb3VudCA9IDFcbiAgXG4gIGNvbmZpZyA9XG4gICAgZGVidWdNZXNzYWdlOiAgIGZhbHNlXG4gICAgaGlkZGVuQ3NzQ2xhc3M6ICdhZGctdmlzdWFsbHktaGlkZGVuJ1xuICBcbiAgIyBDb25zdHJ1Y3Rvci4gU2hvdWxkIG5vdCBiZSBvdmVycmlkZGVuOyB1c2UgQGluaXQoKSBpbnN0ZWFkLlxuICAjXG4gICMgLSBBcmcxOiBUaGUgRE9NIGVsZW1lbnQgb24gd2hpY2ggdGhlIHNjcmlwdCBzaG91bGQgYmUgYXBwbGllZCAod2lsbCBiZSBzYXZlZCBhcyBAJGVsKVxuICAjIC0gQXJnMjogQW4gb3B0aW9uYWwgaGFzaCBvZiBvcHRpb25zIHdoaWNoIHdpbGwgYmUgbWVyZ2VkIGludG8gdGhlIGdsb2JhbCBkZWZhdWx0IGNvbmZpZ1xuICBjb25zdHJ1Y3RvcjogKGVsLCBvcHRpb25zID0ge30pIC0+XG4gICAgQCRlbCA9ICQoZWwpXG5cbiAgICBAY29uZmlnID0gY29uZmlnXG4gICAgZm9yIGtleSwgdmFsIG9mIG9wdGlvbnNcbiAgICAgIEBjb25maWdba2V5XSA9IHZhbFxuICAgIFxuICAgIEBpbml0KClcblxuICAjIER1bW15LCBtdXN0IGJlIG92ZXJyaWRkZW4gaW4gaW5oZXJpdGluZyBjbGFzc2VzLlxuICBpbml0OiAtPlxuICAgIEB0aHJvd01lc3NhZ2VBbmRQcmludE9iamVjdHNUb0NvbnNvbGUgJ0NsYXNzZXMgZXh0ZW5kaW5nIEFwcCBtdXN0IGltcGxlbWVudCBtZXRob2QgaW5pdCgpISdcblxuICAjIFByaW50cyB0aGUgZ2l2ZW4gbWVzc2FnZSB0byB0aGUgY29uc29sZSBpZiBjb25maWdbJ2RlYnVnJ10gaXMgdHJ1ZS5cbiAgZGVidWdNZXNzYWdlOiAobWVzc2FnZSkgLT5cbiAgICBjb25zb2xlLmxvZyBcIkFkZyBkZWJ1ZzogI3ttZXNzYWdlfVwiIGlmIEBjb25maWcuZGVidWdNZXNzYWdlXG5cbiAgIyBFeGVjdXRlcyB0aGUgZ2l2ZW4gc2VsZWN0b3Igb24gQCRlbCBhbmQgcmV0dXJucyB0aGUgZWxlbWVudC4gTWFrZXMgc3VyZSBleGFjdGx5IG9uZSBlbGVtZW50IGV4aXN0cy5cbiAgZmluZE9uZTogKHNlbGVjdG9yKSAtPlxuICAgIHJlc3VsdCA9IEAkZWwuZmluZChzZWxlY3RvcilcbiAgICBzd2l0Y2ggcmVzdWx0Lmxlbmd0aFxuICAgICAgd2hlbiAwIHRoZW4gQHRocm93TWVzc2FnZUFuZFByaW50T2JqZWN0c1RvQ29uc29sZSBcIk5vIG9iamVjdCBmb3VuZCBmb3IgI3tzZWxlY3Rvcn0hXCIsIHJlc3VsdDogcmVzdWx0XG4gICAgICB3aGVuIDEgdGhlbiAkKHJlc3VsdC5maXJzdCgpKVxuICAgICAgZWxzZSBAdGhyb3dNZXNzYWdlQW5kUHJpbnRPYmplY3RzVG9Db25zb2xlIFwiTW9yZSB0aGFuIG9uZSBvYmplY3QgZm91bmQgZm9yICN7c2VsZWN0b3J9IVwiLCByZXN1bHQ6IHJlc3VsdFxuICAgICAgICBcbiAgbmFtZTogLT5cbiAgICBcImFkZy0je0Bjb25zdHJ1Y3Rvci5uYW1lLnRvTG93ZXJDYXNlKCl9XCJcbiAgICAgICAgXG4gIGFkZEFkZ0RhdGFBdHRyaWJ1dGU6ICgkdGFyZ2V0LCBuYW1lLCB2YWx1ZSA9ICcnKSAtPlxuICAgICR0YXJnZXQuYXR0cihAYWRnRGF0YUF0dHJpYnV0ZU5hbWUobmFtZSksIHZhbHVlKVxuICAgICAgICBcbiAgcmVtb3ZlQWRnRGF0YUF0dHJpYnV0ZTogKCR0YXJnZXQsIG5hbWUpIC0+XG4gICAgJHRhcmdldC5yZW1vdmVBdHRyKEBhZGdEYXRhQXR0cmlidXRlTmFtZShuYW1lKSlcbiAgICBcbiAgYWRnRGF0YUF0dHJpYnV0ZU5hbWU6IChuYW1lID0gbnVsbCkgLT5cbiAgICByZXN1bHQgPSBcImRhdGEtI3tAbmFtZSgpfVwiXG4gICAgcmVzdWx0ICs9IFwiLSN7bmFtZX1cIiBpZiBuYW1lXG4gICAgcmVzdWx0XG4gICAgXG4gIHVuaXF1ZUlkOiAobmFtZSkgLT5cbiAgICBbQG5hbWUoKSwgbmFtZSwgdW5pcXVlSWRDb3VudCsrXS5qb2luICctJ1xuICAgIFxuICBsYWJlbE9mSW5wdXQ6ICgkaW5wdXRzKSAtPlxuICAgICRpbnB1dHMubWFwIChpLCBpbnB1dCkgPT5cbiAgICAgICRpbnB1dCA9ICQoaW5wdXQpXG4gICAgICBcbiAgICAgIGlkID0gJGlucHV0LmF0dHIoJ2lkJylcbiAgICAgICRsYWJlbCA9IEBmaW5kT25lKFwibGFiZWxbZm9yPScje2lkfSddXCIpWzBdXG5cbiAgICAgIGlmICRsYWJlbC5sZW5ndGggPT0gMFxuICAgICAgICAkbGFiZWwgPSAkaW5wdXQuY2xvc2VzdCgnbGFiZWwnKVxuICAgICAgICBAdGhyb3dNZXNzYWdlQW5kUHJpbnRPYmplY3RzVG9Db25zb2xlIFwiTm8gY29ycmVzcG9uZGluZyBpbnB1dCBmb3VuZCBmb3IgaW5wdXQhXCIsIGlucHV0OiAkaW5wdXQgaWYgJGxhYmVsLmxlbmd0aCA9PSAwXG5cbiAgICAgICRsYWJlbFxuXG4gIHNob3c6ICgkZWwpIC0+XG4gICAgJGVsLnJlbW92ZUF0dHIoJ2hpZGRlbicpXG4gICAgJGVsLnNob3coKVxuXG4gICAgIyBUT0RPIFdvdWxkIGJlIGNvb2wgdG8gcmVub3VuY2UgQ1NTIGFuZCBzb2xlbHkgdXNlIHRoZSBoaWRkZW4gYXR0cmlidXRlLiBCdXQgalF1ZXJ5J3MgOnZpc2libGUgZG9lc24ndCBzZWVtIHRvIHdvcmsgd2l0aCBpdCE/XG4gICAgIyBAdGhyb3dNZXNzYWdlQW5kUHJpbnRPYmplY3RzVG9Db25zb2xlKFwiRWxlbWVudCBpcyBzdGlsbCBoaWRkZW4sIGFsdGhvdWdoIGhpZGRlbiBhdHRyaWJ1dGUgd2FzIHJlbW92ZWQhIE1ha2Ugc3VyZSB0aGVyZSdzIG5vIENTUyBsaWtlIGRpc3BsYXk6bm9uZSBvciB2aXNpYmlsaXR5OmhpZGRlbiBsZWZ0IG9uIGl0IVwiLCBlbGVtZW50OiAkZWwpIGlmICRlbC5pcygnOmhpZGRlbicpXG5cbiAgaGlkZTogKCRlbCkgLT5cbiAgICAkZWwuYXR0cignaGlkZGVuJywgJycpXG4gICAgJGVsLmhpZGUoKVxuICAgIFxuICB0aHJvd01lc3NhZ2VBbmRQcmludE9iamVjdHNUb0NvbnNvbGU6IChtZXNzYWdlLCBlbGVtZW50cyA9IHt9KSAtPlxuICAgIGNvbnNvbGUubG9nIGVsZW1lbnRzXG4gICAgdGhyb3cgbWVzc2FnZVxuICAgIFxuICB0ZXh0OiAodGV4dCwgb3B0aW9ucyA9IHt9KSAtPlxuICAgIHRleHQgPSBAY29uZmlnW1wiI3t0ZXh0fVRleHRcIl1cbiAgICBcbiAgICBmb3Iga2V5LCB2YWx1ZSBvZiBvcHRpb25zXG4gICAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlIFwiWyN7a2V5fV1cIiwgdmFsdWVcbiAgICAgIFxuICAgIHRleHRcblxuIyBUZXN0ZWQgaW4gSkFXUytJRS9GRiwgTlZEQStGRlxuI1xuIyBLbm93biBpc3N1ZXM6XG4jIC0gSkFXUyBsZWF2ZXMgdGhlIGlucHV0IHdoZW4gdXNpbmcgdXAvZG93biB3aXRob3V0IGVudGVyaW5nIHNvbWV0aGluZyAoSSBndWVzcyB0aGlzIGlzIGR1ZSB0byBzY3JlZW4gbGF5b3V0IGFuZCBjYW4gYmUgY29uc2lkZXJlZCBpbnRlbmRlZClcbiMgLSBBbGVydCBub3QgcGVyY2VpdmFibGUgdXBvbiBvcGVuaW5nIG9wdGlvbnMgdXNpbmcgdXAvZG93blxuIyAgICAgLSBQb3NzaWJsZSBzb2x1dGlvbiAxOiBhbHdheXMgc2hvdyBvcHRpb25zIGNvdW50IHdoZW4gZmlsdGVyIGZvY3VzZWQ/XG4jICAgICAtIFBvc3NpYmxlIHNvbHV0aW9uIDI6IHdhaXQgYSBtb21lbnQgYmVmb3JlIGFkZGluZyB0aGUgYWxlcnQ/XG4jIC0gVm9pY2VPdmVyL2lPUyBhbm5vdW5jZXMgcmFkaW8gYnV0dG9ucyBhcyBkaXNhYmxlZD8hXG4jIC0gaU9TIGRvZXNuJ3Qgc2VsZWN0IGFsbCB0ZXh0IHdoZW4gb3B0aW9uIHdhcyBjaG9zZW5cbiNcbiMgSW4gZ2VuZXJhbDogYWxlcnRzIHNlZW0gdG8gYmUgbW9zdCByb2J1c3QgaW4gYWxsIHJlbGV2YW50IGJyb3dzZXJzLCBidXQgYXJlbid0IHBvbGl0ZS4gTWF5YmUgd2UnbGwgZmluZCBhIGJldHRlciBtZWNoYW5pc20gdG8gc2VydmUgYnJvd3NlcnMgaW5kaXZpZHVhbGx5P1xuY2xhc3MgQWRnLkF1dG9jb21wbGV0ZSBleHRlbmRzIEFkZy5CYXNlXG4gIGNvbmZpZyA9XG4gICAgb3B0aW9uc0NvbnRhaW5lcjogICAgICAnZmllbGRzZXQnXG4gICAgb3B0aW9uc0NvbnRhaW5lckxhYmVsOiAnbGVnZW5kJ1xuICAgIGFsZXJ0c0NvbnRhaW5lcklkOiAgICAgJ2FsZXJ0cydcbiAgICBudW1iZXJJblRvdGFsVGV4dDogICAgICdbbnVtYmVyXSBvcHRpb25zIGluIHRvdGFsJ1xuICAgIG51bWJlckZpbHRlcmVkVGV4dDogICAgJ1tudW1iZXJdIG9mIFt0b3RhbF0gb3B0aW9ucyBmb3IgW2ZpbHRlcl0nXG4gIFxuICBpbml0OiAtPlxuICAgICMgTWVyZ2UgY29uZmlnIGludG8gZXhpc3Rpbmcgb25lIChub3QgbmljZSwgc2VlIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQ3NzIxNjk5LylcbiAgICBmb3Iga2V5LCB2YWwgb2YgY29uZmlnXG4gICAgICBAY29uZmlnW2tleV0gPSB2YWxcbiAgICAgIFxuICAgIGpzb25PcHRpb25zID0gQCRlbC5hdHRyKEBhZGdEYXRhQXR0cmlidXRlTmFtZSgpKVxuICAgIGlmIGpzb25PcHRpb25zXG4gICAgICBmb3Iga2V5LCB2YWwgb2YganNvbk9wdGlvbnNcbiAgICAgICAgQGNvbmZpZ1trZXldID0gdmFsXG4gICAgXG4gICAgQGRlYnVnTWVzc2FnZSAnc3RhcnQnXG5cbiAgICBAaW5pdEZpbHRlcigpXG4gICAgQGluaXRPcHRpb25zKClcbiAgICBAaW5pdEFsZXJ0cygpXG4gICAgXG4gICAgQGFwcGx5Q2hlY2tlZE9wdGlvblRvRmlsdGVyKClcbiAgICBAYW5ub3VuY2VPcHRpb25zTnVtYmVyKCcnKVxuXG4gICAgQGF0dGFjaEV2ZW50cygpXG4gICAgXG4gIGluaXRGaWx0ZXI6IC0+XG4gICAgQCRmaWx0ZXIgPSBAZmluZE9uZSgnaW5wdXRbdHlwZT1cInRleHRcIl0nKVxuICAgIEBhZGRBZGdEYXRhQXR0cmlidXRlKEAkZmlsdGVyLCAnZmlsdGVyJylcbiAgICBAJGZpbHRlci5hdHRyKCdhdXRvY29tcGxldGUnLCAnb2ZmJylcbiAgICBAJGZpbHRlci5hdHRyKCdhcmlhLWV4cGFuZGVkJywgJ2ZhbHNlJylcbiAgICBcbiAgaW5pdE9wdGlvbnM6IC0+XG4gICAgQCRvcHRpb25zQ29udGFpbmVyID0gQGZpbmRPbmUoQGNvbmZpZy5vcHRpb25zQ29udGFpbmVyKVxuICAgIEBhZGRBZGdEYXRhQXR0cmlidXRlKEAkb3B0aW9uc0NvbnRhaW5lciwgJ29wdGlvbnMnKVxuICAgIFxuICAgIEAkb3B0aW9uc0NvbnRhaW5lckxhYmVsID0gQGZpbmRPbmUoQGNvbmZpZy5vcHRpb25zQ29udGFpbmVyTGFiZWwpXG4gICAgQCRvcHRpb25zQ29udGFpbmVyTGFiZWwuYWRkQ2xhc3MoQGNvbmZpZy5oaWRkZW5Dc3NDbGFzcylcbiAgICBcbiAgICBAJG9wdGlvbnMgPSBAJG9wdGlvbnNDb250YWluZXIuZmluZCgnaW5wdXRbdHlwZT1cInJhZGlvXCJdJylcbiAgICBAYWRkQWRnRGF0YUF0dHJpYnV0ZShAbGFiZWxPZklucHV0KEAkb3B0aW9ucyksICdvcHRpb24nKVxuICAgIEAkb3B0aW9ucy5hZGRDbGFzcyhAY29uZmlnLmhpZGRlbkNzc0NsYXNzKVxuICAgIFxuICBpbml0QWxlcnRzOiAtPlxuICAgIEAkYWxlcnRzQ29udGFpbmVyID0gJChcIjxkaXYgaWQ9JyN7QHVuaXF1ZUlkKEBjb25maWcuYWxlcnRzQ29udGFpbmVySWQpfSc+PC9kaXY+XCIpXG4gICAgQCRvcHRpb25zQ29udGFpbmVyTGFiZWwuYWZ0ZXIoQCRhbGVydHNDb250YWluZXIpXG4gICAgQCRmaWx0ZXIuYXR0cignYXJpYS1kZXNjcmliZWRieScsIFtAJGZpbHRlci5hdHRyKCdhcmlhLWRlc2NyaWJlZGJ5JyksIEAkYWxlcnRzQ29udGFpbmVyLmF0dHIoJ2lkJyldLmpvaW4oJyAnKS50cmltKCkpXG4gICAgQGFkZEFkZ0RhdGFBdHRyaWJ1dGUoQCRhbGVydHNDb250YWluZXIsICdhbGVydHMnKVxuICBcbiAgYXR0YWNoRXZlbnRzOiAtPlxuICAgIEBhdHRhY2hDbGlja0V2ZW50VG9GaWx0ZXIoKVxuICAgIEBhdHRhY2hDaGFuZ2VFdmVudFRvRmlsdGVyKClcbiAgICBcbiAgICBAYXR0YWNoRXNjYXBlS2V5VG9GaWx0ZXIoKVxuICAgIEBhdHRhY2hFbnRlcktleVRvRmlsdGVyKClcbiAgICBAYXR0YWNoVGFiS2V5VG9GaWx0ZXIoKVxuICAgIEBhdHRhY2hVcERvd25LZXlzVG9GaWx0ZXIoKVxuICAgIFxuICAgIEBhdHRhY2hDaGFuZ2VFdmVudFRvT3B0aW9ucygpXG4gICAgQGF0dGFjaENsaWNrRXZlbnRUb09wdGlvbnMoKVxuICAgIFxuICBhdHRhY2hDbGlja0V2ZW50VG9GaWx0ZXI6IC0+XG4gICAgQCRmaWx0ZXIuY2xpY2sgPT5cbiAgICAgIEBkZWJ1Z01lc3NhZ2UgJ2NsaWNrIGZpbHRlcidcbiAgICAgIGlmIEAkb3B0aW9uc0NvbnRhaW5lci5pcygnOnZpc2libGUnKVxuICAgICAgICBAaGlkZU9wdGlvbnMoKVxuICAgICAgZWxzZVxuICAgICAgICBAc2hvd09wdGlvbnMoKVxuICAgICAgXG4gIGF0dGFjaEVzY2FwZUtleVRvRmlsdGVyOiAtPlxuICAgIEAkZmlsdGVyLmtleWRvd24gKGUpID0+XG4gICAgICBpZiBlLndoaWNoID09IDI3XG4gICAgICAgIGlmIEAkb3B0aW9uc0NvbnRhaW5lci5pcygnOnZpc2libGUnKVxuICAgICAgICAgIEBhcHBseUNoZWNrZWRPcHRpb25Ub0ZpbHRlckFuZFJlc2V0T3B0aW9ucygpXG4gICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpXG4gICAgICAgIGVsc2UgaWYgQCRvcHRpb25zLmlzKCc6Y2hlY2tlZCcpXG4gICAgICAgICAgQCRvcHRpb25zLnByb3AoJ2NoZWNrZWQnLCBmYWxzZSlcbiAgICAgICAgICBAYXBwbHlDaGVja2VkT3B0aW9uVG9GaWx0ZXJBbmRSZXNldE9wdGlvbnMoKVxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKVxuICAgICAgICBlbHNlICMgTmVlZGVkIGZvciBhdXRvbWF0aWMgdGVzdGluZyBvbmx5XG4gICAgICAgICAgJCgnYm9keScpLmFwcGVuZCgnPHA+RXNjIHBhc3NlZCBvbi48L3A+JylcbiAgICAgIFxuICBhdHRhY2hFbnRlcktleVRvRmlsdGVyOiAtPlxuICAgIEAkZmlsdGVyLmtleWRvd24gKGUpID0+XG4gICAgICBpZiBlLndoaWNoID09IDEzXG4gICAgICAgIEBkZWJ1Z01lc3NhZ2UgJ2VudGVyJ1xuICAgICAgICBpZiBAJG9wdGlvbnNDb250YWluZXIuaXMoJzp2aXNpYmxlJylcbiAgICAgICAgICBAYXBwbHlDaGVja2VkT3B0aW9uVG9GaWx0ZXJBbmRSZXNldE9wdGlvbnMoKVxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKVxuICAgICAgICBlbHNlICMgTmVlZGVkIGZvciBhdXRvbWF0aWMgdGVzdGluZyBvbmx5XG4gICAgICAgICAgJCgnYm9keScpLmFwcGVuZCgnPHA+RW50ZXIgcGFzc2VkIG9uLjwvcD4nKVxuICAgICAgXG4gIGF0dGFjaFRhYktleVRvRmlsdGVyOiAtPlxuICAgIEAkZmlsdGVyLmtleWRvd24gKGUpID0+XG4gICAgICBpZiBlLndoaWNoID09IDlcbiAgICAgICAgQGRlYnVnTWVzc2FnZSAndGFiJ1xuICAgICAgICBpZiBAJG9wdGlvbnNDb250YWluZXIuaXMoJzp2aXNpYmxlJylcbiAgICAgICAgICBAYXBwbHlDaGVja2VkT3B0aW9uVG9GaWx0ZXJBbmRSZXNldE9wdGlvbnMoKVxuICAgICAgXG4gIGF0dGFjaFVwRG93bktleXNUb0ZpbHRlcjogLT5cbiAgICBAJGZpbHRlci5rZXlkb3duIChlKSA9PlxuICAgICAgaWYgZS53aGljaCA9PSAzOCB8fCBlLndoaWNoID09IDQwXG4gICAgICAgIGlmIEAkb3B0aW9uc0NvbnRhaW5lci5pcygnOnZpc2libGUnKVxuICAgICAgICAgIGlmIGUud2hpY2ggPT0gMzhcbiAgICAgICAgICAgIEBtb3ZlU2VsZWN0aW9uKCd1cCcpXG4gICAgICAgICAgZWxzZVxuICAgICAgICAgICAgQG1vdmVTZWxlY3Rpb24oJ2Rvd24nKVxuICAgICAgICBlbHNlXG4gICAgICAgICAgQHNob3dPcHRpb25zKClcbiAgICAgICBcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpICMgVE9ETzogVGVzdCFcbiAgICBcbiAgc2hvd09wdGlvbnM6IC0+XG4gICAgQGRlYnVnTWVzc2FnZSAnKHNob3cgb3B0aW9ucyknXG4gICAgQHNob3coQCRvcHRpb25zQ29udGFpbmVyKVxuICAgIEAkZmlsdGVyLmF0dHIoJ2FyaWEtZXhwYW5kZWQnLCAndHJ1ZScpXG4gICAgXG4gIGhpZGVPcHRpb25zOiAtPlxuICAgIEBkZWJ1Z01lc3NhZ2UgJyhoaWRlIG9wdGlvbnMpJ1xuICAgIEBoaWRlKEAkb3B0aW9uc0NvbnRhaW5lcilcbiAgICBAJGZpbHRlci5hdHRyKCdhcmlhLWV4cGFuZGVkJywgJ2ZhbHNlJylcbiAgICBcbiAgbW92ZVNlbGVjdGlvbjogKGRpcmVjdGlvbikgLT5cbiAgICAkdmlzaWJsZU9wdGlvbnMgPSBAJG9wdGlvbnMuZmlsdGVyKCc6dmlzaWJsZScpXG4gICAgXG4gICAgbWF4SW5kZXggPSAkdmlzaWJsZU9wdGlvbnMubGVuZ3RoIC0gMVxuICAgIGN1cnJlbnRJbmRleCA9ICR2aXNpYmxlT3B0aW9ucy5pbmRleCgkdmlzaWJsZU9wdGlvbnMucGFyZW50KCkuZmluZCgnOmNoZWNrZWQnKSkgIyBUT0RPOiBpcyBwYXJlbnQoKSBnb29kIGhlcmU/IVxuICAgIFxuICAgIHVwY29taW5nSW5kZXggPSBpZiBkaXJlY3Rpb24gPT0gJ3VwJ1xuICAgICAgICAgICAgICAgICAgICAgIGlmIGN1cnJlbnRJbmRleCA8PSAwXG4gICAgICAgICAgICAgICAgICAgICAgICBtYXhJbmRleFxuICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRJbmRleCAtIDFcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgIGlmIGN1cnJlbnRJbmRleCA9PSBtYXhJbmRleFxuICAgICAgICAgICAgICAgICAgICAgICAgMFxuICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRJbmRleCArIDFcblxuICAgICR1cGNvbWluZ09wdGlvbiA9ICQoJHZpc2libGVPcHRpb25zW3VwY29taW5nSW5kZXhdKVxuICAgICR1cGNvbWluZ09wdGlvbi5wcm9wKCdjaGVja2VkJywgdHJ1ZSkudHJpZ2dlcignY2hhbmdlJylcbiAgICBcbiAgYXR0YWNoQ2hhbmdlRXZlbnRUb09wdGlvbnM6IC0+XG4gICAgQCRvcHRpb25zLmNoYW5nZSAoZSkgPT5cbiAgICAgIEBkZWJ1Z01lc3NhZ2UgJ29wdGlvbiBjaGFuZ2UnXG4gICAgICBAYXBwbHlDaGVja2VkT3B0aW9uVG9GaWx0ZXIoKVxuICAgICAgQCRmaWx0ZXIuZm9jdXMoKS5zZWxlY3QoKVxuXG4gIGFwcGx5Q2hlY2tlZE9wdGlvblRvRmlsdGVyQW5kUmVzZXRPcHRpb25zOiAtPlxuICAgIEBhcHBseUNoZWNrZWRPcHRpb25Ub0ZpbHRlcigpXG4gICAgQGhpZGVPcHRpb25zKClcbiAgICBAZmlsdGVyT3B0aW9ucygpXG4gICAgICBcbiAgYXBwbHlDaGVja2VkT3B0aW9uVG9GaWx0ZXI6IC0+XG4gICAgQGRlYnVnTWVzc2FnZSAnKGFwcGx5IG9wdGlvbiB0byBmaWx0ZXIpJ1xuICAgIFxuICAgICRwcmV2aW91c2x5Q2hlY2tlZE9wdGlvbkxhYmVsID0gJChcIlsje0BhZGdEYXRhQXR0cmlidXRlTmFtZSgnb3B0aW9uLXNlbGVjdGVkJyl9XVwiKVxuICAgIGlmICRwcmV2aW91c2x5Q2hlY2tlZE9wdGlvbkxhYmVsLmxlbmd0aCA9PSAxXG4gICAgICBAcmVtb3ZlQWRnRGF0YUF0dHJpYnV0ZSgkcHJldmlvdXNseUNoZWNrZWRPcHRpb25MYWJlbCwgJ29wdGlvbi1zZWxlY3RlZCcpXG4gICBcbiAgICAkY2hlY2tlZE9wdGlvbiA9IEAkb3B0aW9ucy5maWx0ZXIoJzpjaGVja2VkJylcbiAgICBpZiAkY2hlY2tlZE9wdGlvbi5sZW5ndGggPT0gMVxuICAgICAgJGNoZWNrZWRPcHRpb25MYWJlbCA9IEBsYWJlbE9mSW5wdXQoJGNoZWNrZWRPcHRpb24pXG4gICAgICBAJGZpbHRlci52YWwoJC50cmltKCRjaGVja2VkT3B0aW9uTGFiZWwudGV4dCgpKSlcbiAgICAgIEBhZGRBZGdEYXRhQXR0cmlidXRlKCRjaGVja2VkT3B0aW9uTGFiZWwsICdvcHRpb24tc2VsZWN0ZWQnKVxuICAgIGVsc2VcbiAgICAgIEAkZmlsdGVyLnZhbCgnJylcbiAgICAgIFxuICBhdHRhY2hDbGlja0V2ZW50VG9PcHRpb25zOiAtPlxuICAgIEAkb3B0aW9ucy5jbGljayAoZSkgPT5cbiAgICAgIEBkZWJ1Z01lc3NhZ2UgJ2NsaWNrIG9wdGlvbidcbiAgICAgIEBoaWRlT3B0aW9ucygpXG4gICAgICBcbiAgYXR0YWNoQ2hhbmdlRXZlbnRUb0ZpbHRlcjogLT5cbiAgICBAJGZpbHRlci5vbiAnaW5wdXQgcHJvcGVydHljaGFuZ2UgcGFzdGUnLCAoZSkgPT5cbiAgICAgIEBkZWJ1Z01lc3NhZ2UgJyhmaWx0ZXIgY2hhbmdlZCknXG4gICAgICBAZmlsdGVyT3B0aW9ucyhlLnRhcmdldC52YWx1ZSlcbiAgICAgIEBzaG93T3B0aW9ucygpXG4gICAgICBcbiAgZmlsdGVyT3B0aW9uczogKGZpbHRlciA9ICcnKSAtPlxuICAgIGZ1enp5RmlsdGVyID0gQGZ1enppZnlGaWx0ZXIoZmlsdGVyKVxuICAgIHZpc2libGVOdW1iZXIgPSAwXG4gICAgXG4gICAgQCRvcHRpb25zLmVhY2ggKGksIGVsKSA9PlxuICAgICAgJG9wdGlvbiA9ICQoZWwpXG4gICAgICAkb3B0aW9uQ29udGFpbmVyID0gJG9wdGlvbi5wYXJlbnQoKVxuXG4gICAgICByZWdleCA9IG5ldyBSZWdFeHAoZnV6enlGaWx0ZXIsICdpJylcbiAgICAgIGlmIHJlZ2V4LnRlc3QoJG9wdGlvbkNvbnRhaW5lci50ZXh0KCkpXG4gICAgICAgIHZpc2libGVOdW1iZXIrK1xuICAgICAgICBAc2hvdygkb3B0aW9uQ29udGFpbmVyKVxuICAgICAgZWxzZVxuICAgICAgICBAaGlkZSgkb3B0aW9uQ29udGFpbmVyKVxuICAgICAgICBcbiAgICBAYW5ub3VuY2VPcHRpb25zTnVtYmVyKGZpbHRlciwgdmlzaWJsZU51bWJlcilcbiAgICBcbiAgYW5ub3VuY2VPcHRpb25zTnVtYmVyOiAoZmlsdGVyID0gQCRmaWx0ZXIudmFsKCksIG51bWJlciA9IEAkb3B0aW9ucy5sZW5ndGgpIC0+XG4gICAgQCRhbGVydHNDb250YWluZXIuZmluZCgncCcpLnJlbW92ZSgpICMgUmVtb3ZlIHByZXZpb3VzIGFsZXJ0cyAoSSdtIG5vdCBzdXJlIHdoZXRoZXIgdGhpcyBpcyB0aGUgYmVzdCBzb2x1dGlvbiwgbWF5YmUgaGlkaW5nIHRoZW0gd291bGQgYmUgbW9yZSByb2J1c3Q/KVxuICAgIFxuICAgIG1lc3NhZ2UgPSBpZiBmaWx0ZXIgPT0gJydcbiAgICAgICAgICAgICAgICBAdGV4dCgnbnVtYmVySW5Ub3RhbCcsIG51bWJlcjogbnVtYmVyKVxuICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgQHRleHQoJ251bWJlckZpbHRlcmVkJywgbnVtYmVyOiBudW1iZXIsIHRvdGFsOiBAJG9wdGlvbnMubGVuZ3RoLCBmaWx0ZXI6IFwiPGtiZD4je2ZpbHRlcn08L2tiZD5cIilcbiAgICAgIFxuICAgIEAkYWxlcnRzQ29udGFpbmVyLmFwcGVuZChcIjxwIHJvbGU9J2FsZXJ0Jz4je21lc3NhZ2V9PC9wPlwiKVxuICAgICAgICBcbiAgZnV6emlmeUZpbHRlcjogKGZpbHRlcikgLT5cbiAgICBpID0gMFxuICAgIGZ1enppZmllZEZpbHRlciA9ICcnXG4gICAgd2hpbGUgaSA8IGZpbHRlci5sZW5ndGhcbiAgICAgIGVzY2FwZWRDaGFyYWN0ZXIgPSBmaWx0ZXIuY2hhckF0KGkpLnJlcGxhY2UoL1tcXC1cXFtcXF1cXC9cXHtcXH1cXChcXClcXCpcXCtcXD9cXC5cXFxcXFxeXFwkXFx8XS9nLCBcIlxcXFwkJlwiKSAjIFNlZSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zNDQ2MTcwL2VzY2FwZS1zdHJpbmctZm9yLXVzZS1pbi1qYXZhc2NyaXB0LXJlZ2V4XG4gICAgICBmdXp6aWZpZWRGaWx0ZXIgKz0gXCIje2VzY2FwZWRDaGFyYWN0ZXJ9Lio/XCJcbiAgICAgIGkrK1xuICAgICAgXG4gICAgZnV6emlmaWVkRmlsdGVyXG4gICAgXG4kKGRvY3VtZW50KS5yZWFkeSAtPlxuICAkKCdbZGF0YS1hZGctYXV0b2NvbXBsZXRlXScpLmVhY2ggLT5cbiAgICBuZXcgQWRnLkF1dG9jb21wbGV0ZSBAIl19
//# sourceURL=coffeescript

Company

  • About
  • Blog
  • Careers
  • Contact

Services

  • Accessibility Audits
  • Accessibility Consulting
  • VPAT/ACR
  • Accessibility Trainings

Compliance

  • WCAG
  • ADA
  • Section 508
  • EN 301 549
  • EAA
  • AODA Compliance Services — Make Your Digital Assets Accessible in Ontario
  • ACA

Resources

  • Accessibility Resources
  • Understanding WCAG
  • WCAG Checklist
  • Understanding WAI-ARIA

Legal

  • Privacy Policy
  • Terms and Conditions
  • Disclaimer
  • Accessibility Statement for digitala11y.com
  • Sitemap

© 2025 DigitalA11Y
All Rights Reserved

Linkedin Twitter Facebook Instagram YouTube

DigitalA11Y
Plot No 108, 3rd Cross Rd, Saipuri Colony,
Hastinapuri Colony, Sainikpuri, Secunderabad -500094
Telangana, India.

Tel:(+91)99082 66680,
E-mail: [email protected]

Scroll to top
  • Home
  • Services
    • WCAG Audit Services
    • VPAT/ACR Services
    • Accessibility Consulting
    • PDF Remediation
    • Accessibility Trainings
    • Website Remediation
    • Design Audit
  • Free Tools
    • Accessibility Checker
    • A11Y Cost Calculator
    • A11Y Bookmarklets
    • Color Contrast Extension
    • WCAG Contrast Checker
  • Resources
    • A11Y Articles
    • WCAG Primer
    • ARIA Cheatsheet
    • A11Y Tools
    • A11Y Patterns
    • A11Y Cheatsheets
  • Contact