text: define("ace/ext/chromevox", ["require", "exports", "module", "ace/editor", "ace/config"], function (require, exports, module) {
      var cvoxAce = {};
      cvoxAce.SpeechProperty;
      cvoxAce.Cursor;
      cvoxAce.Token;
      cvoxAce.Annotation;
      var CONSTANT_PROP = {
          'rate': 0.8,
          'pitch': 0.4,
          'volume': 0.9
      };
      var DEFAULT_PROP = {
          'rate': 1,
          'pitch': 0.5,
          'volume': 0.9
      };
      var ENTITY_PROP = {
          'rate': 0.8,
          'pitch': 0.8,
          'volume': 0.9
      };
      var KEYWORD_PROP = {
          'rate': 0.8,
          'pitch': 0.3,
          'volume': 0.9
      };
      var STORAGE_PROP = {
          'rate': 0.8,
          'pitch': 0.7,
          'volume': 0.9
      };
      var VARIABLE_PROP = {
          'rate': 0.8,
          'pitch': 0.8,
          'volume': 0.9
      };
      var DELETED_PROP = {
          'punctuationEcho': 'none',
          'relativePitch': -0.6
      };
      var ERROR_EARCON = 'ALERT_NONMODAL';
      var MODE_SWITCH_EARCON = 'ALERT_MODAL';
      var NO_MATCH_EARCON = 'INVALID_KEYPRESS';
      var INSERT_MODE_STATE = 'insertMode';
      var COMMAND_MODE_STATE = 'start';
  
      var REPLACE_LIST = [
          {
              substr: ';',
              newSubstr: ' semicolon '
          },
          {
              substr: ':',
              newSubstr: ' colon '
          }
      ];
      var Command = {
          SPEAK_ANNOT: 'annots',
          SPEAK_ALL_ANNOTS: 'all_annots',
          TOGGLE_LOCATION: 'toggle_location',
          SPEAK_MODE: 'mode',
          SPEAK_ROW_COL: 'row_col',
          TOGGLE_DISPLACEMENT: 'toggle_displacement',
          FOCUS_TEXT: 'focus_text'
      };
      var KEY_PREFIX = 'CONTROL + SHIFT ';
      cvoxAce.editor = null;
      var lastCursor = null;
      var annotTable = {};
      var shouldSpeakRowLocation = false;
      var shouldSpeakDisplacement = false;
      var changed = false;
      var vimState = null;
      var keyCodeToShortcutMap = {};
      var cmdToShortcutMap = {};
      var getKeyShortcutString = function (keyCode) {
          return KEY_PREFIX + String.fromCharCode(keyCode);
      };
      var isVimMode = function () {
          var keyboardHandler = cvoxAce.editor.keyBinding.getKeyboardHandler();
          return keyboardHandler.$id === 'ace/keyboard/vim';
      };
      var getCurrentToken = function (cursor) {
          return cvoxAce.editor.getSession().getTokenAt(cursor.row, cursor.column + 1);
      };
      var getCurrentLine = function (cursor) {
          return cvoxAce.editor.getSession().getLine(cursor.row);
      };
      var onRowChange = function (currCursor) {
          if (annotTable[currCursor.row]) {
              cvox.Api.playEarcon(ERROR_EARCON);
          }
          if (shouldSpeakRowLocation) {
              cvox.Api.stop();
              speakChar(currCursor);
              speakTokenQueue(getCurrentToken(currCursor));
              speakLine(currCursor.row, 1);
          } else {
              speakLine(currCursor.row, 0);
          }
      };
      var isWord = function (cursor) {
          var line = getCurrentLine(cursor);
          var lineSuffix = line.substr(cursor.column - 1);
          if (cursor.column === 0) {
              lineSuffix = ' ' + line;
          }
          var firstWordRegExp = /^\W(\w+)/;
          var words = firstWordRegExp.exec(lineSuffix);
          return words !== null;
      };
      var rules = {
          'constant': {
              prop: CONSTANT_PROP
          },
          'entity': {
              prop: ENTITY_PROP
          },
          'keyword': {
              prop: KEYWORD_PROP
          },
          'storage': {
              prop: STORAGE_PROP
          },
          'variable': {
              prop: VARIABLE_PROP
          },
          'meta': {
              prop: DEFAULT_PROP,
              replace: [
                  {
                      substr: '</',
                      newSubstr: ' closing tag '
                  },
                  {
                      substr: '/>',
                      newSubstr: ' close tag '
                  },
                  {
                      substr: '<',
                      newSubstr: ' tag start '
                  },
                  {
                      substr: '>',
                      newSubstr: ' tag end '
                  }
              ]
          }
      };
      var DEFAULT_RULE = {
          prop: DEFAULT_RULE
      };
      var expand = function (value, replaceRules) {
          var newValue = value;
          for (var i = 0; i < replaceRules.length; i++) {
              var replaceRule = replaceRules[i];
              var regexp = new RegExp(replaceRule.substr, 'g');
              newValue = newValue.replace(regexp, replaceRule.newSubstr);
          }
          return newValue;
      };
      var mergeTokens = function (tokens, start, end) {
          var newToken = {};
          newToken.value = '';
          newToken.type = tokens[start].type;
          for (var j = start; j < end; j++) {
              newToken.value += tokens[j].value;
          }
          return newToken;
      };
      var mergeLikeTokens = function (tokens) {
          if (tokens.length <= 1) {
              return tokens;
          }
          var newTokens = [];
          var lastLikeIndex = 0;
          for (var i = 1; i < tokens.length; i++) {
              var lastLikeToken = tokens[lastLikeIndex];
              var currToken = tokens[i];
              if (getTokenRule(lastLikeToken) !== getTokenRule(currToken)) {
                  newTokens.push(mergeTokens(tokens, lastLikeIndex, i));
                  lastLikeIndex = i;
              }
          }
          newTokens.push(mergeTokens(tokens, lastLikeIndex, tokens.length));
          return newTokens;
      };
      var isRowWhiteSpace = function (row) {
          var line = cvoxAce.editor.getSession().getLine(row);
          var whiteSpaceRegexp = /^\s*$/;
          return whiteSpaceRegexp.exec(line) !== null;
      };
      var speakLine = function (row, queue) {
          var tokens = cvoxAce.editor.getSession().getTokens(row);
          if (tokens.length === 0 || isRowWhiteSpace(row)) {
              cvox.Api.playEarcon('EDITABLE_TEXT');
              return;
          }
          tokens = mergeLikeTokens(tokens);
          var firstToken = tokens[0];
          tokens = tokens.filter(function (token) {
              return token !== firstToken;
          });
          speakToken_(firstToken, queue);
          tokens.forEach(speakTokenQueue);
      };
      var speakTokenFlush = function (token) {
          speakToken_(token, 0);
      };
      var speakTokenQueue = function (token) {
          speakToken_(token, 1);
      };
      var getTokenRule = function (token) {
          if (!token || !token.type) {
              return;
          }
          var split = token.type.split('.');
          if (split.length === 0) {
              return;
          }
          var type = split[0];
          var rule = rules[type];
          if (!rule) {
              return DEFAULT_RULE;
          }
          return rule;
      };
      var speakToken_ = function (token, queue) {
          var rule = getTokenRule(token);
          var value = expand(token.value, REPLACE_LIST);
          if (rule.replace) {
              value = expand(value, rule.replace);
          }
          cvox.Api.speak(value, queue, rule.prop);
      };
      var speakChar = function (cursor) {
          var line = getCurrentLine(cursor);
          cvox.Api.speak(line[cursor.column], 1);
      };
      var speakDisplacement = function (lastCursor, currCursor) {
          var line = getCurrentLine(currCursor);
          var displace = line.substring(lastCursor.column, currCursor.column);
          displace = displace.replace(/ /g, ' space ');
          cvox.Api.speak(displace);
      };
      var speakCharOrWordOrLine = function (lastCursor, currCursor) {
          if (Math.abs(lastCursor.column - currCursor.column) !== 1) {
              var currLineLength = getCurrentLine(currCursor).length;
              if (currCursor.column === 0 || currCursor.column === currLineLength) {
                  speakLine(currCursor.row, 0);
                  return;
              }
              if (isWord(currCursor)) {
                  cvox.Api.stop();
                  speakTokenQueue(getCurrentToken(currCursor));
                  return;
              }
          }
          speakChar(currCursor);
      };
      var onColumnChange = function (lastCursor, currCursor) {
          if (!cvoxAce.editor.selection.isEmpty()) {
              speakDisplacement(lastCursor, currCursor);
              cvox.Api.speak('selected', 1);
          } else if (shouldSpeakDisplacement) {
              speakDisplacement(lastCursor, currCursor);
          } else {
              speakCharOrWordOrLine(lastCursor, currCursor);
          }
      };
      var onCursorChange = function (evt) {
          if (changed) {
              changed = false;
              return;
          }
          var currCursor = cvoxAce.editor.selection.getCursor();
          if (currCursor.row !== lastCursor.row) {
              onRowChange(currCursor);
          } else {
              onColumnChange(lastCursor, currCursor);
          }
          lastCursor = currCursor;
      };
      var onSelectionChange = function (evt) {
          if (cvoxAce.editor.selection.isEmpty()) {
              cvox.Api.speak('unselected');
          }
      };
      var onChange = function (delta) {
          switch (delta.action) {
              case 'remove':
                  cvox.Api.speak(delta.text, 0, DELETED_PROP);
                  changed = true;
                  break;
              case 'insert':
                  cvox.Api.speak(delta.text, 0);
                  changed = true;
                  break;
          }
      };
      var isNewAnnotation = function (annot) {
          var row = annot.row;
          var col = annot.column;
          return !annotTable[row] || !annotTable[row][col];
      };
      var populateAnnotations = function (annotations) {
          annotTable = {};
          for (var i = 0; i < annotations.length; i++) {
              var annotation = annotations[i];
              var row = annotation.row;
              var col = annotation.column;
              if (!annotTable[row]) {
                  annotTable[row] = {};
              }
              annotTable[row][col] = annotation;
          }
      };
      var onAnnotationChange = function (evt) {
          var annotations = cvoxAce.editor.getSession().getAnnotations();
          var newAnnotations = annotations.filter(isNewAnnotation);
          if (newAnnotations.length > 0) {
              cvox.Api.playEarcon(ERROR_EARCON);
          }
          populateAnnotations(annotations);
      };
      var speakAnnot = function (annot) {
          var annotText = annot.type + ' ' + annot.text + ' on ' +
              rowColToString(annot.row, annot.column);
          annotText = annotText.replace(';', 'semicolon');
          cvox.Api.speak(annotText, 1);
      };
      var speakAnnotsByRow = function (row) {
          var annots = annotTable[row];
          for (var col in annots) {
              speakAnnot(annots[col]);
          }
      };
      var rowColToString = function (row, col) {
          return 'row ' + (row + 1) + ' column ' + (col + 1);
      };
      var speakCurrRowAndCol = function () {
          cvox.Api.speak(rowColToString(lastCursor.row, lastCursor.column));
      };
      var speakAllAnnots = function () {
          for (var row in annotTable) {
              speakAnnotsByRow(row);
          }
      };
      var speakMode = function () {
          if (!isVimMode()) {
              return;
          }
          switch (cvoxAce.editor.keyBinding.$data.state) {
              case INSERT_MODE_STATE:
                  cvox.Api.speak('Insert mode');
                  break;
              case COMMAND_MODE_STATE:
                  cvox.Api.speak('Command mode');
                  break;
          }
      };
      var toggleSpeakRowLocation = function () {
          shouldSpeakRowLocation = !shouldSpeakRowLocation;
          if (shouldSpeakRowLocation) {
              cvox.Api.speak('Speak location on row change enabled.');
          } else {
              cvox.Api.speak('Speak location on row change disabled.');
          }
      };
      var toggleSpeakDisplacement = function () {
          shouldSpeakDisplacement = !shouldSpeakDisplacement;
          if (shouldSpeakDisplacement) {
              cvox.Api.speak('Speak displacement on column changes.');
          } else {
              cvox.Api.speak('Speak current character or word on column changes.');
          }
      };
      var onKeyDown = function (evt) {
          if (evt.ctrlKey && evt.shiftKey) {
              var shortcut = keyCodeToShortcutMap[evt.keyCode];
              if (shortcut) {
                  shortcut.func();
              }
          }
      };
      var onChangeStatus = function (evt, editor) {
          if (!isVimMode()) {
              return;
          }
          var state = editor.keyBinding.$data.state;
          if (state === vimState) {
              return;
          }
          switch (state) {
              case INSERT_MODE_STATE:
                  cvox.Api.playEarcon(MODE_SWITCH_EARCON);
                  cvox.Api.setKeyEcho(true);
                  break;
              case COMMAND_MODE_STATE:
                  cvox.Api.playEarcon(MODE_SWITCH_EARCON);
                  cvox.Api.setKeyEcho(false);
                  break;
          }
          vimState = state;
      };
      var contextMenuHandler = function (evt) {
          var cmd = evt.detail['customCommand'];
          var shortcut = cmdToShortcutMap[cmd];
          if (shortcut) {
              shortcut.func();
              cvoxAce.editor.focus();
          }
      };
      var initContextMenu = function () {
          var ACTIONS = SHORTCUTS.map(function (shortcut) {
              return {
                  desc: shortcut.desc + getKeyShortcutString(shortcut.keyCode),
                  cmd: shortcut.cmd
              };
          });
          var body = document.querySelector('body');
          body.setAttribute('contextMenuActions', JSON.stringify(ACTIONS));
          body.addEventListener('ATCustomEvent', contextMenuHandler, true);
      };
      var onFindSearchbox = function (evt) {
          if (evt.match) {
              speakLine(lastCursor.row, 0);
          } else {
              cvox.Api.playEarcon(NO_MATCH_EARCON);
          }
      };
      var focus = function () {
          cvoxAce.editor.focus();
      };
      var SHORTCUTS = [
          {
              keyCode: 49,
              func: function () {
                  speakAnnotsByRow(lastCursor.row);
              },
              cmd: Command.SPEAK_ANNOT,
              desc: 'Speak annotations on line'
          },
          {
              keyCode: 50,
              func: speakAllAnnots,
              cmd: Command.SPEAK_ALL_ANNOTS,
              desc: 'Speak all annotations'
          },
          {
              keyCode: 51,
              func: speakMode,
              cmd: Command.SPEAK_MODE,
              desc: 'Speak Vim mode'
          },
          {
              keyCode: 52,
              func: toggleSpeakRowLocation,
              cmd: Command.TOGGLE_LOCATION,
              desc: 'Toggle speak row location'
          },
          {
              keyCode: 53,
              func: speakCurrRowAndCol,
              cmd: Command.SPEAK_ROW_COL,
              desc: 'Speak row and column'
          },
          {
              keyCode: 54,
              func: toggleSpeakDisplacement,
              cmd: Command.TOGGLE_DISPLACEMENT,
              desc: 'Toggle speak displacement'
          },
          {
              keyCode: 55,
              func: focus,
              cmd: Command.FOCUS_TEXT,
              desc: 'Focus text'
          }
      ];
      var onFocus = function (_, editor) {
          cvoxAce.editor = editor;
          editor.getSession().selection.on('changeCursor', onCursorChange);
          editor.getSession().selection.on('changeSelection', onSelectionChange);
          editor.getSession().on('change', onChange);
          editor.getSession().on('changeAnnotation', onAnnotationChange);
          editor.on('changeStatus', onChangeStatus);
          editor.on('findSearchBox', onFindSearchbox);
          editor.container.addEventListener('keydown', onKeyDown);
  
          lastCursor = editor.selection.getCursor();
      };
      var init = function (editor) {
          onFocus(null, editor);
          SHORTCUTS.forEach(function (shortcut) {
              keyCodeToShortcutMap[shortcut.keyCode] = shortcut;
              cmdToShortcutMap[shortcut.cmd] = shortcut;
          });
  
          editor.on('focus', onFocus);
          if (isVimMode()) {
              cvox.Api.setKeyEcho(false);
          }
          initContextMenu();
      };
  
      function cvoxApiExists() {
          return (typeof (cvox) !== 'undefined') && cvox && cvox.Api;
      }
  
      var tries = 0;
      var MAX_TRIES = 15;
  
      function watchForCvoxLoad(editor) {
          if (cvoxApiExists()) {
              init(editor);
          } else {
              tries++;
              if (tries >= MAX_TRIES) {
                  return;
              }
              window.setTimeout(watchForCvoxLoad, 500, editor);
          }
      }
  
      var Editor = require('../editor').Editor;
      require('../config').defineOptions(Editor.prototype, 'editor', {
          enableChromevoxEnhancements: {
              set: function (val) {
                  if (val) {
                      watchForCvoxLoad(this);
                  }
              },
              value: true // turn it on by default or check for window.cvox
          }
      });
  
  });
  (function () {
      window.require(["ace/ext/chromevox"], function () {
      });
  })();
  