code: function TextRange(document, startLine, endLine) {
          this.startLine = startLine;
          this.endLine = endLine;
  
          this.document = document;
          document.addRef();
          // store this-bound versions of listeners so we can remove them later
          this._handleDocumentChange = this._handleDocumentChange.bind(this);
          this._handleDocumentDeleted = this._handleDocumentDeleted.bind(this);
          document.on("change", this._handleDocumentChange);
          document.on("deleted", this._handleDocumentDeleted);
      }
docs: Stores a range of lines that is automatically maintained as the Document changes. The range
  MAY drop out of sync with the Document in certain edge cases; startLine & endLine will become
  null when that happens.
  
  Important: you must dispose() a TextRange when you're done with it. Because TextRange addRef()s
  the Document (in order to listen to it), you will leak Documents otherwise.
  
  TextRange dispatches these events:
  - change -- When the range boundary line numbers change (due to a Document change)
  - contentChange -- When the actual content of the range changes. This might or might not
  be accompanied by a change in the boundary line numbers.
  - lostSync -- When the backing Document changes in such a way that the range can no longer
  accurately be maintained. Generally, occurs whenever an edit spans a range boundary.
  After this, startLine & endLine will be unusable (set to null).
  Also occurs when the document is deleted, though startLine & endLine won't be modified
  These events only ever occur in response to Document changes, so if you are already listening
  to the Document, you could ignore the TextRange events and just read its updated value in your
  own Document change handler.
  
  @constructor
  
  @param {!Document} document
  @param {number} startLine First line in range (0-based, inclusive)
  @param {number} endLine   Last line in range (0-based, inclusive)