Processes an individual gloss element
function processGloss(gloss, callback) {
      if (!(gloss instanceof Element)) {
        var err = new Error('Invalid gloss element');

        if (typeof callback === 'function') {
          callback(err);
        } else {
          throw err;
        }
      }

      var lines = Array.prototype.slice.call(gloss.children);
      var linesToAlign = [];
      var firstRawLine = null;
      var firstRawLineNum = 0;

      triggerEvent(gloss, events.beforeGloss);

      if (firstLineOrig) {
        var firstLine = lines[0];
        addClass(firstLine, classes.original);
      }

      if (lastLineFree) {
        var lastLine = lines[lines.length - 1];
        addClass(lastLine, classes.freeTranslation);
      }

      // process each line in the gloss
      lines.forEach(function (line, lineNum) {
        // don't align lines that are free translations or original,
        // unformatted lines
        var isOrig = hasClass(line, classes.original);
        var isFree = hasClass(line, classes.freeTranslation);
        var shouldSkip = hasClass(line, classes.noAlign);

        var shouldAlign = !isOrig && !isFree && !shouldSkip;

        if (shouldAlign) {
          triggerEvent(line, events.beforeLex, { lineNum: lineNum });
          var tokens = _this2.lex(line.innerHTML);
          triggerEvent(line, events.afterLex, {
            tokens: tokens,
            lineNum: lineNum
          });

          linesToAlign.push(tokens);
          addClass(line, classes.hidden);

          // if this is the first aligned line, mark the location
          // so that the final aligned glosses can be inserted here
          if (!firstRawLine) {
            firstRawLine = line;
            firstRawLineNum = lineNum;
          }
        } else {
          addClass(line, classes.line);
          addClass(line, classes.lineNum + lineNum);
        }
      });

      var lastRawLineNum = firstRawLineNum + (linesToAlign.length - 1);

      triggerEvent(gloss, events.beforeAlign, {
        lines: linesToAlign,
        firstLineNum: firstRawLineNum,
        lastLineNum: lastRawLineNum
      });

      var alignedLines = _this2.align(linesToAlign);

      triggerEvent(gloss, events.afterAlign, {
        lines: alignedLines,
        firstLineNum: firstRawLineNum,
        lastLineNum: lastRawLineNum
      });

      // determine which type of element the aligned glosses should be wrapped in
      var alignedWrapper = undefined;
      if (gloss.tagName === 'UL' || gloss.tagName === 'OL') {
        alignedWrapper = 'li';
      } else {
        alignedWrapper = 'div';
      }

      triggerEvent(gloss, events.beforeFormat, {
        lines: alignedLines,
        firstLineNum: firstRawLineNum,
        lastLineNum: lastRawLineNum
      });

      var formattedLines = _this2.format(alignedLines, alignedWrapper, firstRawLineNum);
      gloss.insertBefore(formattedLines, firstRawLine);

      triggerEvent(formattedLines, events.afterFormat, {
        firstLineNum: firstRawLineNum,
        lastLineNum: lastRawLineNum
      });

      // finish up by adding relevant classes to the main container
      if (!spacing) {
        addClass(gloss, classes.noSpace);
      }

      addClass(gloss, classes.glossed);

      triggerEvent(gloss, events.afterGloss);
    }