Skip to content
Snippets Groups Projects
onDeleteAccount.js 7.67 MiB
Newer Older
  • Learn to ignore specific revisions
  • build-token's avatar
    build-token committed
    227001 227002 227003 227004 227005 227006 227007 227008 227009 227010 227011 227012 227013 227014 227015 227016 227017 227018 227019 227020 227021 227022 227023 227024 227025 227026 227027 227028 227029 227030 227031 227032 227033 227034 227035 227036 227037 227038 227039 227040 227041 227042 227043 227044 227045 227046 227047 227048 227049 227050 227051 227052 227053 227054 227055 227056 227057 227058 227059 227060 227061 227062 227063 227064 227065 227066 227067 227068 227069 227070 227071 227072 227073 227074 227075 227076 227077 227078 227079 227080 227081 227082 227083 227084 227085 227086 227087 227088 227089 227090 227091 227092 227093 227094 227095 227096 227097 227098 227099 227100 227101 227102 227103 227104 227105 227106 227107 227108 227109 227110 227111 227112 227113 227114 227115 227116 227117 227118 227119 227120 227121 227122 227123 227124 227125 227126 227127 227128 227129 227130 227131 227132 227133 227134 227135 227136 227137 227138 227139 227140 227141 227142 227143 227144 227145 227146 227147 227148 227149 227150 227151 227152 227153 227154 227155 227156 227157 227158 227159 227160 227161 227162 227163 227164 227165 227166 227167 227168 227169 227170 227171 227172 227173 227174 227175 227176 227177 227178 227179 227180 227181 227182 227183 227184 227185 227186 227187 227188 227189 227190 227191 227192 227193 227194 227195 227196 227197 227198 227199 227200 227201 227202 227203 227204 227205 227206 227207 227208 227209 227210 227211 227212 227213 227214 227215 227216 227217 227218 227219 227220 227221 227222 227223 227224 227225 227226 227227 227228 227229 227230 227231 227232 227233 227234 227235 227236 227237 227238 227239 227240 227241 227242 227243 227244 227245 227246 227247 227248 227249 227250 227251 227252 227253 227254 227255 227256 227257 227258 227259 227260 227261 227262 227263 227264 227265 227266 227267 227268 227269 227270 227271 227272 227273 227274 227275 227276 227277 227278 227279 227280 227281 227282 227283 227284 227285 227286 227287 227288 227289 227290 227291 227292 227293 227294 227295 227296 227297 227298 227299 227300 227301 227302 227303 227304 227305 227306 227307 227308 227309 227310 227311 227312 227313
        'Ucirc': 219,
        'Ugrave': 217,
        'Uuml': 220,
        'Yacute': 221,
        'aacute': 225,
        'acirc': 226,
        'aelig': 230,
        'agrave': 224,
        'aring': 229,
        'atilde': 227,
        'auml': 228,
        'ccedil': 231,
        'eacute': 233,
        'ecirc': 234,
        'egrave': 232,
        'eth': 240,
        'euml': 235,
        'iacute': 237,
        'icirc': 238,
        'igrave': 236,
        'iuml': 239,
        'ntilde': 241,
        'oacute': 243,
        'ocirc': 244,
        'ograve': 242,
        'oslash': 248,
        'otilde': 245,
        'ouml': 246,
        'szlig': 223,
        'thorn': 254,
        'uacute': 250,
        'ucirc': 251,
        'ugrave': 249,
        'uuml': 252,
        'yacute': 253,
        'yuml': 255,
        'copy': 169,
        'reg': 174,
        'nbsp': 160,
        'iexcl': 161,
        'cent': 162,
        'pound': 163,
        'curren': 164,
        'yen': 165,
        'brvbar': 166,
        'sect': 167,
        'uml': 168,
        'ordf': 170,
        'laquo': 171,
        'not': 172,
        'shy': 173,
        'macr': 175,
        'deg': 176,
        'plusmn': 177,
        'sup1': 185,
        'sup2': 178,
        'sup3': 179,
        'acute': 180,
        'micro': 181,
        'para': 182,
        'middot': 183,
        'cedil': 184,
        'ordm': 186,
        'raquo': 187,
        'frac14': 188,
        'frac12': 189,
        'frac34': 190,
        'iquest': 191,
        'times': 215,
        'divide': 247,
        'OElig': 338,
        'oelig': 339,
        'Scaron': 352,
        'scaron': 353,
        'Yuml': 376,
        'fnof': 402,
        'circ': 710,
        'tilde': 732,
        'Alpha': 913,
        'Beta': 914,
        'Gamma': 915,
        'Delta': 916,
        'Epsilon': 917,
        'Zeta': 918,
        'Eta': 919,
        'Theta': 920,
        'Iota': 921,
        'Kappa': 922,
        'Lambda': 923,
        'Mu': 924,
        'Nu': 925,
        'Xi': 926,
        'Omicron': 927,
        'Pi': 928,
        'Rho': 929,
        'Sigma': 931,
        'Tau': 932,
        'Upsilon': 933,
        'Phi': 934,
        'Chi': 935,
        'Psi': 936,
        'Omega': 937,
        'alpha': 945,
        'beta': 946,
        'gamma': 947,
        'delta': 948,
        'epsilon': 949,
        'zeta': 950,
        'eta': 951,
        'theta': 952,
        'iota': 953,
        'kappa': 954,
        'lambda': 955,
        'mu': 956,
        'nu': 957,
        'xi': 958,
        'omicron': 959,
        'pi': 960,
        'rho': 961,
        'sigmaf': 962,
        'sigma': 963,
        'tau': 964,
        'upsilon': 965,
        'phi': 966,
        'chi': 967,
        'psi': 968,
        'omega': 969,
        'thetasym': 977,
        'upsih': 978,
        'piv': 982,
        'ensp': 8194,
        'emsp': 8195,
        'thinsp': 8201,
        'zwnj': 8204,
        'zwj': 8205,
        'lrm': 8206,
        'rlm': 8207,
        'ndash': 8211,
        'mdash': 8212,
        'lsquo': 8216,
        'rsquo': 8217,
        'sbquo': 8218,
        'ldquo': 8220,
        'rdquo': 8221,
        'bdquo': 8222,
        'dagger': 8224,
        'Dagger': 8225,
        'bull': 8226,
        'hellip': 8230,
        'permil': 8240,
        'prime': 8242,
        'Prime': 8243,
        'lsaquo': 8249,
        'rsaquo': 8250,
        'oline': 8254,
        'frasl': 8260,
        'euro': 8364,
        'image': 8465,
        'weierp': 8472,
        'real': 8476,
        'trade': 8482,
        'alefsym': 8501,
        'larr': 8592,
        'uarr': 8593,
        'rarr': 8594,
        'darr': 8595,
        'harr': 8596,
        'crarr': 8629,
        'lArr': 8656,
        'uArr': 8657,
        'rArr': 8658,
        'dArr': 8659,
        'hArr': 8660,
        'forall': 8704,
        'part': 8706,
        'exist': 8707,
        'empty': 8709,
        'nabla': 8711,
        'isin': 8712,
        'notin': 8713,
        'ni': 8715,
        'prod': 8719,
        'sum': 8721,
        'minus': 8722,
        'lowast': 8727,
        'radic': 8730,
        'prop': 8733,
        'infin': 8734,
        'ang': 8736,
        'and': 8743,
        'or': 8744,
        'cap': 8745,
        'cup': 8746,
        'int': 8747,
        'there4': 8756,
        'sim': 8764,
        'cong': 8773,
        'asymp': 8776,
        'ne': 8800,
        'equiv': 8801,
        'le': 8804,
        'ge': 8805,
        'sub': 8834,
        'sup': 8835,
        'nsub': 8836,
        'sube': 8838,
        'supe': 8839,
        'oplus': 8853,
        'otimes': 8855,
        'perp': 8869,
        'sdot': 8901,
        'lceil': 8968,
        'rceil': 8969,
        'lfloor': 8970,
        'rfloor': 8971,
        'lang': 9001,
        'rang': 9002,
        'loz': 9674,
        'spades': 9824,
        'clubs': 9827,
        'hearts': 9829,
        'diams': 9830
      }
    
      Object.keys(sax.ENTITIES).forEach(function (key) {
        var e = sax.ENTITIES[key]
        var s = typeof e === 'number' ? String.fromCharCode(e) : e
        sax.ENTITIES[key] = s
      })
    
      for (var s in sax.STATE) {
        sax.STATE[sax.STATE[s]] = s
      }
    
      // shorthand
      S = sax.STATE
    
      function emit (parser, event, data) {
        parser[event] && parser[event](data)
      }
    
      function emitNode (parser, nodeType, data) {
        if (parser.textNode) closeText(parser)
        emit(parser, nodeType, data)
      }
    
      function closeText (parser) {
        parser.textNode = textopts(parser.opt, parser.textNode)
        if (parser.textNode) emit(parser, 'ontext', parser.textNode)
        parser.textNode = ''
      }
    
      function textopts (opt, text) {
        if (opt.trim) text = text.trim()
        if (opt.normalize) text = text.replace(/\s+/g, ' ')
        return text
      }
    
      function error (parser, er) {
        closeText(parser)
        if (parser.trackPosition) {
          er += '\nLine: ' + parser.line +
            '\nColumn: ' + parser.column +
            '\nChar: ' + parser.c
        }
        er = new Error(er)
        parser.error = er
        emit(parser, 'onerror', er)
        return parser
      }
    
      function end (parser) {
        if (parser.sawRoot && !parser.closedRoot) strictFail(parser, 'Unclosed root tag')
        if ((parser.state !== S.BEGIN) &&
          (parser.state !== S.BEGIN_WHITESPACE) &&
          (parser.state !== S.TEXT)) {
          error(parser, 'Unexpected end')
        }
        closeText(parser)
        parser.c = ''
        parser.closed = true
        emit(parser, 'onend')
        SAXParser.call(parser, parser.strict, parser.opt)
        return parser
      }
    
      function strictFail (parser, message) {
        if (typeof parser !== 'object' || !(parser instanceof SAXParser)) {
          throw new Error('bad call to strictFail')
        }
        if (parser.strict) {
          error(parser, message)
        }
      }
    
      function newTag (parser) {
        if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase]()
        var parent = parser.tags[parser.tags.length - 1] || parser
        var tag = parser.tag = { name: parser.tagName, attributes: {} }
    
        // will be overridden if tag contails an xmlns="foo" or xmlns:foo="bar"
        if (parser.opt.xmlns) {
          tag.ns = parent.ns
        }
        parser.attribList.length = 0
        emitNode(parser, 'onopentagstart', tag)
      }
    
      function qname (name, attribute) {
        var i = name.indexOf(':')
        var qualName = i < 0 ? [ '', name ] : name.split(':')
        var prefix = qualName[0]
        var local = qualName[1]
    
    build-token's avatar
    build-token committed
        // <x "xmlns"="http://foo">
        if (attribute && name === 'xmlns') {
          prefix = 'xmlns'
          local = ''
        }
    
    build-token's avatar
    build-token committed
        return { prefix: prefix, local: local }
      }
    
    build-token's avatar
    build-token committed
      function attrib (parser) {
        if (!parser.strict) {
          parser.attribName = parser.attribName[parser.looseCase]()
        }
    
    build-token's avatar
    build-token committed
        if (parser.attribList.indexOf(parser.attribName) !== -1 ||
          parser.tag.attributes.hasOwnProperty(parser.attribName)) {
          parser.attribName = parser.attribValue = ''
          return
        }
    
    build-token's avatar
    build-token committed
        if (parser.opt.xmlns) {
          var qn = qname(parser.attribName, true)
          var prefix = qn.prefix
          var local = qn.local
    
          if (prefix === 'xmlns') {
            // namespace binding attribute. push the binding into scope
            if (local === 'xml' && parser.attribValue !== XML_NAMESPACE) {
              strictFail(parser,
                'xml: prefix must be bound to ' + XML_NAMESPACE + '\n' +
                'Actual: ' + parser.attribValue)
            } else if (local === 'xmlns' && parser.attribValue !== XMLNS_NAMESPACE) {
              strictFail(parser,
                'xmlns: prefix must be bound to ' + XMLNS_NAMESPACE + '\n' +
                'Actual: ' + parser.attribValue)
            } else {
              var tag = parser.tag
              var parent = parser.tags[parser.tags.length - 1] || parser
              if (tag.ns === parent.ns) {
                tag.ns = Object.create(parent.ns)
              }
              tag.ns[local] = parser.attribValue
            }
          }
    
    build-token's avatar
    build-token committed
          // defer onattribute events until all attributes have been seen
          // so any new bindings can take effect. preserve attribute order
          // so deferred events can be emitted in document order
          parser.attribList.push([parser.attribName, parser.attribValue])
        } else {
          // in non-xmlns mode, we can emit the event right away
          parser.tag.attributes[parser.attribName] = parser.attribValue
          emitNode(parser, 'onattribute', {
            name: parser.attribName,
            value: parser.attribValue
          })
        }
    
    build-token's avatar
    build-token committed
        parser.attribName = parser.attribValue = ''
      }
    
    build-token's avatar
    build-token committed
      function openTag (parser, selfClosing) {
        if (parser.opt.xmlns) {
          // emit namespace binding events
          var tag = parser.tag
    
    build-token's avatar
    build-token committed
          // add namespace info to tag
          var qn = qname(parser.tagName)
          tag.prefix = qn.prefix
          tag.local = qn.local
          tag.uri = tag.ns[qn.prefix] || ''
    
    build-token's avatar
    build-token committed
          if (tag.prefix && !tag.uri) {
            strictFail(parser, 'Unbound namespace prefix: ' +
              JSON.stringify(parser.tagName))
            tag.uri = qn.prefix
          }
    
    build-token's avatar
    build-token committed
          var parent = parser.tags[parser.tags.length - 1] || parser
          if (tag.ns && parent.ns !== tag.ns) {
            Object.keys(tag.ns).forEach(function (p) {
              emitNode(parser, 'onopennamespace', {
                prefix: p,
                uri: tag.ns[p]
              })
            })
          }
    
    build-token's avatar
    build-token committed
          // handle deferred onattribute events
          // Note: do not apply default ns to attributes:
          //   http://www.w3.org/TR/REC-xml-names/#defaulting
          for (var i = 0, l = parser.attribList.length; i < l; i++) {
            var nv = parser.attribList[i]
            var name = nv[0]
            var value = nv[1]
            var qualName = qname(name, true)
            var prefix = qualName.prefix
            var local = qualName.local
            var uri = prefix === '' ? '' : (tag.ns[prefix] || '')
            var a = {
              name: name,
              value: value,
              prefix: prefix,
              local: local,
              uri: uri
            }
    
            // if there's any attributes with an undefined namespace,
            // then fail on them now.
            if (prefix && prefix !== 'xmlns' && !uri) {
              strictFail(parser, 'Unbound namespace prefix: ' +
                JSON.stringify(prefix))
              a.uri = prefix
            }
            parser.tag.attributes[name] = a
            emitNode(parser, 'onattribute', a)
          }
          parser.attribList.length = 0
        }
    
        parser.tag.isSelfClosing = !!selfClosing
    
        // process the tag
        parser.sawRoot = true
        parser.tags.push(parser.tag)
        emitNode(parser, 'onopentag', parser.tag)
        if (!selfClosing) {
          // special case for <script> in non-strict mode.
          if (!parser.noscript && parser.tagName.toLowerCase() === 'script') {
            parser.state = S.SCRIPT
          } else {
            parser.state = S.TEXT
          }
          parser.tag = null
          parser.tagName = ''
        }
        parser.attribName = parser.attribValue = ''
        parser.attribList.length = 0
      }
    
    build-token's avatar
    build-token committed
      function closeTag (parser) {
        if (!parser.tagName) {
          strictFail(parser, 'Weird empty close tag.')
          parser.textNode += '</>'
          parser.state = S.TEXT
          return
        }
    
    build-token's avatar
    build-token committed
        if (parser.script) {
          if (parser.tagName !== 'script') {
            parser.script += '</' + parser.tagName + '>'
            parser.tagName = ''
            parser.state = S.SCRIPT
            return
          }
          emitNode(parser, 'onscript', parser.script)
          parser.script = ''
        }
    
    build-token's avatar
    build-token committed
        // first make sure that the closing tag actually exists.
        // <a><b></c></b></a> will close everything, otherwise.
        var t = parser.tags.length
        var tagName = parser.tagName
        if (!parser.strict) {
          tagName = tagName[parser.looseCase]()
        }
        var closeTo = tagName
        while (t--) {
          var close = parser.tags[t]
          if (close.name !== closeTo) {
            // fail the first time in strict mode
            strictFail(parser, 'Unexpected close tag')
          } else {
            break
          }
        }
    
    build-token's avatar
    build-token committed
        // didn't find it.  we already failed for strict, so just abort.
        if (t < 0) {
          strictFail(parser, 'Unmatched closing tag: ' + parser.tagName)
          parser.textNode += '</' + parser.tagName + '>'
          parser.state = S.TEXT
          return
        }
        parser.tagName = tagName
        var s = parser.tags.length
        while (s-- > t) {
          var tag = parser.tag = parser.tags.pop()
          parser.tagName = parser.tag.name
          emitNode(parser, 'onclosetag', parser.tagName)
    
    build-token's avatar
    build-token committed
          var x = {}
          for (var i in tag.ns) {
            x[i] = tag.ns[i]
          }
    
    build-token's avatar
    build-token committed
          var parent = parser.tags[parser.tags.length - 1] || parser
          if (parser.opt.xmlns && tag.ns !== parent.ns) {
            // remove namespace bindings introduced by tag
            Object.keys(tag.ns).forEach(function (p) {
              var n = tag.ns[p]
              emitNode(parser, 'onclosenamespace', { prefix: p, uri: n })
            })
          }
        }
        if (t === 0) parser.closedRoot = true
        parser.tagName = parser.attribValue = parser.attribName = ''
        parser.attribList.length = 0
        parser.state = S.TEXT
      }
    
    build-token's avatar
    build-token committed
      function parseEntity (parser) {
        var entity = parser.entity
        var entityLC = entity.toLowerCase()
        var num
        var numStr = ''
    
    build-token's avatar
    build-token committed
        if (parser.ENTITIES[entity]) {
          return parser.ENTITIES[entity]
        }
        if (parser.ENTITIES[entityLC]) {
          return parser.ENTITIES[entityLC]
        }
        entity = entityLC
        if (entity.charAt(0) === '#') {
          if (entity.charAt(1) === 'x') {
            entity = entity.slice(2)
            num = parseInt(entity, 16)
            numStr = num.toString(16)
          } else {
            entity = entity.slice(1)
            num = parseInt(entity, 10)
            numStr = num.toString(10)
          }
        }
        entity = entity.replace(/^0+/, '')
        if (isNaN(num) || numStr.toLowerCase() !== entity) {
          strictFail(parser, 'Invalid character entity')
          return '&' + parser.entity + ';'
        }
    
    build-token's avatar
    build-token committed
        return String.fromCodePoint(num)
      }
    
    build-token's avatar
    build-token committed
      function beginWhiteSpace (parser, c) {
        if (c === '<') {
          parser.state = S.OPEN_WAKA
          parser.startTagPosition = parser.position
        } else if (!isWhitespace(c)) {
          // have to process this as a text node.
          // weird, but happens.
          strictFail(parser, 'Non-whitespace before first tag.')
          parser.textNode = c
          parser.state = S.TEXT
        }
      }
    
    build-token's avatar
    build-token committed
      function charAt (chunk, i) {
        var result = ''
        if (i < chunk.length) {
          result = chunk.charAt(i)
        }
        return result
      }
    
    build-token's avatar
    build-token committed
      function write (chunk) {
        var parser = this
        if (this.error) {
          throw this.error
        }
        if (parser.closed) {
          return error(parser,
            'Cannot write after close. Assign an onready handler.')
        }
        if (chunk === null) {
          return end(parser)
        }
        if (typeof chunk === 'object') {
          chunk = chunk.toString()
        }
        var i = 0
        var c = ''
        while (true) {
          c = charAt(chunk, i++)
          parser.c = c
    
    build-token's avatar
    build-token committed
          if (!c) {
            break
          }
    
    build-token's avatar
    build-token committed
          if (parser.trackPosition) {
            parser.position++
            if (c === '\n') {
              parser.line++
              parser.column = 0
            } else {
              parser.column++
            }
          }
    
    build-token's avatar
    build-token committed
          switch (parser.state) {
            case S.BEGIN:
              parser.state = S.BEGIN_WHITESPACE
              if (c === '\uFEFF') {
                continue
              }
              beginWhiteSpace(parser, c)
              continue
    
    build-token's avatar
    build-token committed
            case S.BEGIN_WHITESPACE:
              beginWhiteSpace(parser, c)
              continue
    
    build-token's avatar
    build-token committed
            case S.TEXT:
              if (parser.sawRoot && !parser.closedRoot) {
                var starti = i - 1
                while (c && c !== '<' && c !== '&') {
                  c = charAt(chunk, i++)
                  if (c && parser.trackPosition) {
                    parser.position++
                    if (c === '\n') {
                      parser.line++
                      parser.column = 0
                    } else {
                      parser.column++
                    }
                  }
                }
                parser.textNode += chunk.substring(starti, i - 1)
              }
              if (c === '<' && !(parser.sawRoot && parser.closedRoot && !parser.strict)) {
                parser.state = S.OPEN_WAKA
                parser.startTagPosition = parser.position
              } else {
                if (!isWhitespace(c) && (!parser.sawRoot || parser.closedRoot)) {
                  strictFail(parser, 'Text data outside of root node.')
                }
                if (c === '&') {
                  parser.state = S.TEXT_ENTITY
                } else {
                  parser.textNode += c
                }
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.SCRIPT:
              // only non-strict
              if (c === '<') {
                parser.state = S.SCRIPT_ENDING
              } else {
                parser.script += c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.SCRIPT_ENDING:
              if (c === '/') {
                parser.state = S.CLOSE_TAG
              } else {
                parser.script += '<' + c
                parser.state = S.SCRIPT
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.OPEN_WAKA:
              // either a /, ?, !, or text is coming next.
              if (c === '!') {
                parser.state = S.SGML_DECL
                parser.sgmlDecl = ''
              } else if (isWhitespace(c)) {
                // wait for it...
              } else if (isMatch(nameStart, c)) {
                parser.state = S.OPEN_TAG
                parser.tagName = c
              } else if (c === '/') {
                parser.state = S.CLOSE_TAG
                parser.tagName = ''
              } else if (c === '?') {
                parser.state = S.PROC_INST
                parser.procInstName = parser.procInstBody = ''
              } else {
                strictFail(parser, 'Unencoded <')
                // if there was some whitespace, then add that in.
                if (parser.startTagPosition + 1 < parser.position) {
                  var pad = parser.position - parser.startTagPosition
                  c = new Array(pad).join(' ') + c
                }
                parser.textNode += '<' + c
                parser.state = S.TEXT
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.SGML_DECL:
              if ((parser.sgmlDecl + c).toUpperCase() === CDATA) {
                emitNode(parser, 'onopencdata')
                parser.state = S.CDATA
                parser.sgmlDecl = ''
                parser.cdata = ''
              } else if (parser.sgmlDecl + c === '--') {
                parser.state = S.COMMENT
                parser.comment = ''
                parser.sgmlDecl = ''
              } else if ((parser.sgmlDecl + c).toUpperCase() === DOCTYPE) {
                parser.state = S.DOCTYPE
                if (parser.doctype || parser.sawRoot) {
                  strictFail(parser,
                    'Inappropriately located doctype declaration')
                }
                parser.doctype = ''
                parser.sgmlDecl = ''
              } else if (c === '>') {
                emitNode(parser, 'onsgmldeclaration', parser.sgmlDecl)
                parser.sgmlDecl = ''
                parser.state = S.TEXT
              } else if (isQuote(c)) {
                parser.state = S.SGML_DECL_QUOTED
                parser.sgmlDecl += c
              } else {
                parser.sgmlDecl += c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.SGML_DECL_QUOTED:
              if (c === parser.q) {
                parser.state = S.SGML_DECL
                parser.q = ''
              }
              parser.sgmlDecl += c
              continue
    
    build-token's avatar
    build-token committed
            case S.DOCTYPE:
              if (c === '>') {
                parser.state = S.TEXT
                emitNode(parser, 'ondoctype', parser.doctype)
                parser.doctype = true // just remember that we saw it.
              } else {
                parser.doctype += c
                if (c === '[') {
                  parser.state = S.DOCTYPE_DTD
                } else if (isQuote(c)) {
                  parser.state = S.DOCTYPE_QUOTED
                  parser.q = c
                }
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.DOCTYPE_QUOTED:
              parser.doctype += c
              if (c === parser.q) {
                parser.q = ''
                parser.state = S.DOCTYPE
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.DOCTYPE_DTD:
              parser.doctype += c
              if (c === ']') {
                parser.state = S.DOCTYPE
              } else if (isQuote(c)) {
                parser.state = S.DOCTYPE_DTD_QUOTED
                parser.q = c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.DOCTYPE_DTD_QUOTED:
              parser.doctype += c
              if (c === parser.q) {
                parser.state = S.DOCTYPE_DTD
                parser.q = ''
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.COMMENT:
              if (c === '-') {
                parser.state = S.COMMENT_ENDING
              } else {
                parser.comment += c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.COMMENT_ENDING:
              if (c === '-') {
                parser.state = S.COMMENT_ENDED
                parser.comment = textopts(parser.opt, parser.comment)
                if (parser.comment) {
                  emitNode(parser, 'oncomment', parser.comment)
                }
                parser.comment = ''
              } else {
                parser.comment += '-' + c
                parser.state = S.COMMENT
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.COMMENT_ENDED:
              if (c !== '>') {
                strictFail(parser, 'Malformed comment')
                // allow <!-- blah -- bloo --> in non-strict mode,
                // which is a comment of " blah -- bloo "
                parser.comment += '--' + c
                parser.state = S.COMMENT
              } else {
                parser.state = S.TEXT
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.CDATA:
              if (c === ']') {
                parser.state = S.CDATA_ENDING
              } else {
                parser.cdata += c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.CDATA_ENDING:
              if (c === ']') {
                parser.state = S.CDATA_ENDING_2
              } else {
                parser.cdata += ']' + c
                parser.state = S.CDATA
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.CDATA_ENDING_2:
              if (c === '>') {
                if (parser.cdata) {
                  emitNode(parser, 'oncdata', parser.cdata)
                }
                emitNode(parser, 'onclosecdata')
                parser.cdata = ''
                parser.state = S.TEXT
              } else if (c === ']') {
                parser.cdata += ']'
              } else {
                parser.cdata += ']]' + c
                parser.state = S.CDATA
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.PROC_INST:
              if (c === '?') {
                parser.state = S.PROC_INST_ENDING
              } else if (isWhitespace(c)) {
                parser.state = S.PROC_INST_BODY
              } else {
                parser.procInstName += c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.PROC_INST_BODY:
              if (!parser.procInstBody && isWhitespace(c)) {
                continue
              } else if (c === '?') {
                parser.state = S.PROC_INST_ENDING
              } else {
                parser.procInstBody += c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.PROC_INST_ENDING:
              if (c === '>') {
                emitNode(parser, 'onprocessinginstruction', {
                  name: parser.procInstName,
                  body: parser.procInstBody
                })
                parser.procInstName = parser.procInstBody = ''
                parser.state = S.TEXT
              } else {
                parser.procInstBody += '?' + c
                parser.state = S.PROC_INST_BODY
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.OPEN_TAG:
              if (isMatch(nameBody, c)) {
                parser.tagName += c
              } else {
                newTag(parser)
                if (c === '>') {
                  openTag(parser)
                } else if (c === '/') {
                  parser.state = S.OPEN_TAG_SLASH
                } else {
                  if (!isWhitespace(c)) {
                    strictFail(parser, 'Invalid character in tag name')
                  }
                  parser.state = S.ATTRIB
                }
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.OPEN_TAG_SLASH:
              if (c === '>') {
                openTag(parser, true)
                closeTag(parser)
              } else {
                strictFail(parser, 'Forward-slash in opening tag not followed by >')
                parser.state = S.ATTRIB
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.ATTRIB:
              // haven't read the attribute name yet.
              if (isWhitespace(c)) {
                continue
              } else if (c === '>') {
                openTag(parser)
              } else if (c === '/') {
                parser.state = S.OPEN_TAG_SLASH
              } else if (isMatch(nameStart, c)) {
                parser.attribName = c
                parser.attribValue = ''
                parser.state = S.ATTRIB_NAME
              } else {
                strictFail(parser, 'Invalid attribute name')
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.ATTRIB_NAME:
              if (c === '=') {
                parser.state = S.ATTRIB_VALUE
              } else if (c === '>') {
                strictFail(parser, 'Attribute without value')
                parser.attribValue = parser.attribName
                attrib(parser)
                openTag(parser)
              } else if (isWhitespace(c)) {
                parser.state = S.ATTRIB_NAME_SAW_WHITE
              } else if (isMatch(nameBody, c)) {
                parser.attribName += c
              } else {
                strictFail(parser, 'Invalid attribute name')
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.ATTRIB_NAME_SAW_WHITE:
              if (c === '=') {
                parser.state = S.ATTRIB_VALUE
              } else if (isWhitespace(c)) {
                continue
              } else {
                strictFail(parser, 'Attribute without value')
                parser.tag.attributes[parser.attribName] = ''
                parser.attribValue = ''
                emitNode(parser, 'onattribute', {
                  name: parser.attribName,
                  value: ''
                })
                parser.attribName = ''
                if (c === '>') {
                  openTag(parser)
                } else if (isMatch(nameStart, c)) {
                  parser.attribName = c
                  parser.state = S.ATTRIB_NAME
                } else {
                  strictFail(parser, 'Invalid attribute name')
                  parser.state = S.ATTRIB
                }
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.ATTRIB_VALUE:
              if (isWhitespace(c)) {
                continue
              } else if (isQuote(c)) {
                parser.q = c
                parser.state = S.ATTRIB_VALUE_QUOTED
              } else {
                strictFail(parser, 'Unquoted attribute value')
                parser.state = S.ATTRIB_VALUE_UNQUOTED
                parser.attribValue = c
              }
              continue
    
    build-token's avatar
    build-token committed
            case S.ATTRIB_VALUE_QUOTED:
              if (c !== parser.q) {
                if (c === '&') {
                  parser.state = S.ATTRIB_VALUE_ENTITY_Q
                } else {
                  parser.attribValue += c
                }
                continue
              }
              attrib(parser)
              parser.q = ''
              parser.state = S.ATTRIB_VALUE_CLOSED
              continue