gt:         int glue = str.indexOf('-');
context: /*
   * Copyright (C) 2015 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.databinding.tool.store;
  import org.antlr.v4.runtime.ParserRuleContext;
  import org.antlr.v4.runtime.Token;
  import org.apache.commons.lang3.StringUtils;
  
  import android.databinding.tool.processing.scopes.LocationScopeProvider;
  
  import java.util.Arrays;
  import java.util.List;
  
  import javax.xml.bind.annotation.XmlAccessType;
  import javax.xml.bind.annotation.XmlAccessorType;
  import javax.xml.bind.annotation.XmlAttribute;
  import javax.xml.bind.annotation.XmlElement;
  
  /**
   * Identifies the range of a code block inside a file or a string.
   * Note that, unlike antlr4 tokens, the line positions start from 0 (to be compatible with Studio).
   * <p>
   * Both start and end line/column indices are inclusive.
   */
  @XmlAccessorType(XmlAccessType.NONE)
  public class Location {
      public static final int NaN = -1;
      @XmlAttribute(name = "startLine")
      public int startLine;
      @XmlAttribute(name = "startOffset")
      public int startOffset;
      @XmlAttribute(name = "endLine")
      public int endLine;
      @XmlAttribute(name = "endOffset")
      public int endOffset;
      @XmlElement(name = "parentLocation")
      public Location parentLocation;
  
      // for XML unmarshalling
      public Location() {
          startOffset = endOffset = startLine = endLine = NaN;
      }
  
      public Location(Location other) {
          startOffset = other.startOffset;
          endOffset = other.endOffset;
          startLine = other.startLine;
          endLine = other.endLine;
      }
  
      public Location(Token start, Token end) {
          if (start == null) {
              startLine = startOffset = NaN;
          } else {
              startLine = start.getLine() - 1; //token lines start from 1
              startOffset = start.getCharPositionInLine();
          }
  
          if (end == null) {
              endLine = endOffset = NaN;
          } else {
              endLine = end.getLine() - 1; // token lines start from 1
              String endText = end.getText();
              int lastLineStart = endText.lastIndexOf(System.lineSeparator());
              String lastLine = lastLineStart < 0 ? endText : endText.substring(lastLineStart + 1);
              endOffset = end.getCharPositionInLine() + lastLine.length() - 1;//end is inclusive
          }
      }
  
      public Location(ParserRuleContext context) {
          this(context == null ? null : context.getStart(),
                  context == null ? null : context.getStop());
      }
  
      public Location(int startLine, int startOffset, int endLine, int endOffset) {
          this.startOffset = startOffset;
          this.startLine = startLine;
          this.endLine = endLine;
          this.endOffset = endOffset;
      }
  
      @Override
      public String toString() {
          return "Location{" +
                  "startLine=" + startLine +
                  ", startOffset=" + startOffset +
                  ", endLine=" + endLine +
                  ", endOffset=" + endOffset +
                  ", parentLocation=" + parentLocation +
                  '}';
      }
  
      public void setParentLocation(Location parentLocation) {
          this.parentLocation = parentLocation;
      }
  
      @Override
      public boolean equals(Object o) {
          if (this == o) {
              return true;
          }
          if (o == null || getClass() != o.getClass()) {
              return false;
          }
  
          Location location = (Location) o;
  
          if (endLine != location.endLine) {
              return false;
          }
          if (endOffset != location.endOffset) {
              return false;
          }
          if (startLine != location.startLine) {
              return false;
          }
          if (startOffset != location.startOffset) {
              return false;
          }
          if (parentLocation != null ? !parentLocation.equals(location.parentLocation)
                  : location.parentLocation != null) {
              return false;
          }
  
          return true;
      }
  
      @Override
      public int hashCode() {
          int result = startLine;
          result = 31 * result + startOffset;
          result = 31 * result + endLine;
          result = 31 * result + endOffset;
          return result;
      }
  
      public boolean isValid() {
          return startLine != NaN && endLine != NaN && startOffset != NaN && endOffset != NaN;
      }
  
      public boolean contains(Location other) {
          if (startLine > other.startLine) {
              return false;
          }
          if (startLine == other.startLine && startOffset > other.startOffset) {
              return false;
          }
          if (endLine < other.endLine) {
              return false;
          }
          if (endLine == other.endLine && endOffset < other.endOffset) {
              return false;
          }
          return true;
      }
  
      private Location getValidParentAbsoluteLocation() {
          if (parentLocation == null) {
              return null;
          }
          if (parentLocation.isValid()) {
              return parentLocation.toAbsoluteLocation();
          }
          return parentLocation.getValidParentAbsoluteLocation();
      }
  
      public Location toAbsoluteLocation() {
          Location absoluteParent = getValidParentAbsoluteLocation();
          if (absoluteParent == null) {
              return this;
          }
          Location copy = new Location(this);
          boolean sameLine = copy.startLine == copy.endLine;
          if (copy.startLine == 0) {
              copy.startOffset += absoluteParent.startOffset;
          }
          if (sameLine) {
              copy.endOffset += absoluteParent.startOffset;
          }
  
          copy.startLine += absoluteParent.startLine;
          copy.endLine += absoluteParent.startLine;
          return copy;
      }
  
      public String toUserReadableString() {
          return startLine + ":" + startOffset + " - " + endLine + ":" + endOffset;
      }
  
      public static Location fromUserReadableString(String str) {
  