anchor.diff:          throw new WebSocketException("Received masked frame from server");
         }
         _state = MASK;
  -      _remainingMaskingKeyBytes = 4;
       } else {
         if (_serverSide) {
           throw new WebSocketException("Received unmasked frame from client");
  
positive.code:     int count = buffer.length;
      int index = 0;
      int lastIndex = count;
      try {
        if (_state == CLOSED) {
          throw new WebSocketException("Data on closed connection");
        }
        if (_state == FAILURE) {
          throw new WebSocketException("Data on failed connection");
        }
        while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
          int byte = buffer[index];
          switch (_state) {
            case START:
              _fin = (byte & 0x80) != 0;
              if ((byte & 0x70) != 0) {
                // The RSV1, RSV2 bits RSV3 most be all zero.
                throw new WebSocketException("Protocol error");
              }
              _opcode = (byte & 0xF);
              switch (_opcode) {
              case _WebSocketOpcode.CONTINUATION:
                if (_currentMessageType == _WebSocketMessageType.NONE) {
                  throw new WebSocketException("Protocol error");
                }
                break;
  
              case _WebSocketOpcode.TEXT:
                if (_currentMessageType != _WebSocketMessageType.NONE) {
                  throw new WebSocketException("Protocol error");
                }
                _currentMessageType = _WebSocketMessageType.TEXT;
                _controller = new StreamController(sync: true);
                _controller.stream
                    .transform(UTF8.decoder)
                    .fold(new StringBuffer(), (buffer, str) => buffer..write(str))
                    .then((buffer) {
                      _eventSink.add(buffer.toString());
                    }, onError: _eventSink.addError);
                break;
  
              case _WebSocketOpcode.BINARY:
                if (_currentMessageType != _WebSocketMessageType.NONE) {
                  throw new WebSocketException("Protocol error");
                }
                _currentMessageType = _WebSocketMessageType.BINARY;
                _controller = new StreamController(sync: true);
                _controller.stream
                    .fold(new BytesBuilder(), (buffer, data) => buffer..add(data))
                    .then((buffer) {
                      _eventSink.add(buffer.takeBytes());
                    }, onError: _eventSink.addError);
                break;
  
              case _WebSocketOpcode.CLOSE:
              case _WebSocketOpcode.PING:
              case _WebSocketOpcode.PONG:
                // Control frames cannot be fragmented.
                if (!_fin) throw new WebSocketException("Protocol error");
                break;
  
              default:
                throw new WebSocketException("Protocol error");
              }
              _state = LEN_FIRST;
              break;
  
            case LEN_FIRST:
              _masked = (byte & 0x80) != 0;
              _len = byte & 0x7F;
              if (_isControlFrame() && _len > 125) {
                throw new WebSocketException("Protocol error");
              }
              if (_len < 126) {
                _lengthDone();
              } else if (_len == 126) {
                _len = 0;
                _remainingLenBytes = 2;
                _state = LEN_REST;
              } else if (_len == 127) {
                _len = 0;
                _remainingLenBytes = 8;
                _state = LEN_REST;
              }
              break;
  
            case LEN_REST:
              _len = _len << 8 | byte;
              _remainingLenBytes--;
              if (_remainingLenBytes == 0) {
                _lengthDone();
              }
              break;
  
            case MASK:
              _maskingKey = _maskingKey << 8 | byte;
              _remainingMaskingKeyBytes--;
              if (_remainingMaskingKeyBytes == 0) {
                _maskDone();
              }
              break;
  
            case PAYLOAD:
              // The payload is not handled one byte at a time but in blocks.
              int payload;
              if (lastIndex - index <= _remainingPayloadBytes) {
                payload = lastIndex - index;
              } else {
                payload = _remainingPayloadBytes;
              }
              _remainingPayloadBytes -= payload;
  
              // Unmask payload if masked.
              if (_masked) {
                for (int i = 0; i < payload; i++) {
                  int maskingByte =
                      ((_maskingKey >> ((3 - _unmaskingIndex) * 8)) & 0xFF);
                  buffer[index + i] = buffer[index + i] ^ maskingByte;
                  _unmaskingIndex = (_unmaskingIndex + 1) % 4;
                }
              }
  
              if (_isControlFrame()) {
                if (payload > 0) {
                  // Allocate a buffer for collecting the control frame
                  // payload if any.
                  if (_controlPayload == null) {
                    _controlPayload = new List<int>();
                  }
                  _controlPayload.addAll(buffer.sublist(index, index + payload));
                  index += payload;
                }
  
                if (_remainingPayloadBytes == 0) {
                  _controlFrameEnd();
                }
              } else {
                if (_currentMessageType != _WebSocketMessageType.TEXT &&
                    _currentMessageType != _WebSocketMessageType.BINARY) {
                    throw new WebSocketException("Protocol error");
                }
                _controller.add(
                    new Uint8List.view(buffer.buffer, index, payload));
                index += payload;
                if (_remainingPayloadBytes == 0) {
                  _messageFrameEnd();
                }
              }
  
              // Hack - as we always do index++ below.
              index--;
              break;
          }
  
          // Move to the next byte.
          index++;
        }
      } catch (e, stackTrace) {
        _state = FAILURE;
        _eventSink.addError(e, stackTrace);
      }
    }
  
  
negative.code:         break;
  
        case _WebSocketOpcode.PING:
          _eventSink.add(new _WebSocketPing(_payload.takeBytes()));
          break;
  
        case _WebSocketOpcode.PONG:
          _eventSink.add(new _WebSocketPong(_payload.takeBytes()));
          break;
      }
      _prepareForNextFrame();
  