Tells if the given content line is the last line of a possible header of this definition kind.

@param line The line to test.
@return true if the last line of a header have been recognized or false.
325112
public boolean isLastHeaderLine(String line) {
        return lastLineDetectionPattern != null && line != null && lastLineDetectionPattern.matcher(line).matches();
    }
936669
private boolean parseLine(final String line, final StringBuilder sql) {
        String trimmedLine = trimLine(line);
        sql.append(trimmedLine).append(LINE_SEPARATOR);

        return isFullCommand(trimmedLine);
    }
1202714
protected function isParagraphEnd($line)
	{
		if (empty($line) ||
			ltrim($line) === '' ||
			$this->identifyHeadline($line) ||
			$this->identifyHr($line) ||
			$this->identifyUl($line) ||
			$this->identifyOl($line) ||
			$this->identifyTable($line) ||
			$this->identifyCode($line) ||
			$this->identifyRawHtml($line))
		{
			return true;
		}
		return false;
	}
503902
public boolean removeLeadingEmptyLines()
    {
        boolean wasEmpty = false;
        Line line = this.lines;
        while (line != null && line.isEmpty)
        {
            this.removeLine(line);
            line = this.lines;
            wasEmpty = true;
        }
        return wasEmpty;
    }
436174
public function headerSent(string &$file = null, int &$line = null) : bool
    {
        return headers_sent($file, $line);
    }
941269
public static int lengthWithoutLinefeed(CharSequence line) {
    int length = line.length();
    while(length > 0) {
      char last = line.charAt(length - 1);
      if(last != '\n' && last != '\r') {
        break;
      }
      --length;
    }
    return length;
  }
870554
private boolean isMathExpression(String line) {
        String cleanLine = cleanLine(line).trim();
        boolean mathExpression = false;
        if (cleanLine.startsWith(DEFINE)) {
            return true;
        } else if (cleanLine.matches(CODE_LINE_SUFFIX)) {
            return true;
        }

        // go forward
        int index = cleanLine.indexOf(COPYRIGHT_SYMBOL);
        for (int i = index + 1; i < cleanLine.length(); i++) {
            char c = cleanLine.charAt(i);
            if (c == Constants.OPEN_BRACKET || c == Constants.CLOSE_BRACKET || c == Constants.WHITESPACE_CHAR) {
                continue;
            } else if (MATH_SYMBOLS.contains(c)) {
                mathExpression = true;
                break;
            } else {
                break;
            }
        }

        // go backwards
        if (mathExpression) {
            for (int i = index - 1; i >= 0; i--) {
                char c = cleanLine.charAt(i);
                if (c == Constants.OPEN_BRACKET || c == Constants.CLOSE_BRACKET || c == Constants.WHITESPACE_CHAR) {
                    continue;
                } else if (MATH_SYMBOLS.contains(c)) {
                    mathExpression = true;
                    break;
                } else {
                    break;
                }
            }
        }
        return mathExpression;
    }
404714
protected List<String> parseWords(String line) {
        List<String> words = new ArrayList<String>();
        boolean insideWord = !isSpace(line.charAt(0));
        int last = 0;
        for( int i = 0; i < line.length(); i++) {
            char c = line.charAt(i);

            if( insideWord ) {
                // see if its at the end of a word
                if( isSpace(c)) {
                    words.add( line.substring(last,i) );
                    insideWord = false;
                }
            } else {
                if( !isSpace(c)) {
                    last = i;
                    insideWord = true;
                }
            }
        }

        // if the line ended add the final word
        if( insideWord ) {
            words.add( line.substring(last));
        }
        return words;
    }
101456
private String getTextLine(String[] textLines, int line)
	{
		return (isIgnoreTrailingWhiteSpaces()) ? textLines[line].trim() : textLines[line];
	}
1140853
private boolean commentLinesBefore( String content, int line ) {
        int offset = rootElement.getElement(line).getStartOffset();
        // Start of comment not found, nothing to do
        int startDelimiter = lastIndexOf(content, getStartDelimiter(), offset - 2);
        if (startDelimiter < 0)
            return false;
        // Matching start/end of comment found, nothing to do
        int endDelimiter = indexOf(content, getEndDelimiter(), startDelimiter);
        if (endDelimiter < offset & endDelimiter != -1)
            return false;
        // End of comment not found, highlight the lines
        doc.setCharacterAttributes(startDelimiter, offset - startDelimiter + 1, comment, false);
        return true;
    }
1226943
private void checkForFinalBoundary(String boundaryLine) throws IOException {
    if (boundaryLine.equals(boundary + "--")) {
      hasNext = false;
      inputStream.close();
    }
  }
30315
function(line) {
    header.resolveTempo();
    multilineVars.is_in_header = false;	// We should have gotten a key header by now, but just in case, this is definitely out of the header.
    var i = 0;
    var startOfLine = multilineVars.iChar;
    //multilineVars.havent_set_length = false;	// To late to set this now.
    // see if there is nothing but a comment on this line. If so, just ignore it. A full line comment is optional white space followed by %
    while (tokenizer.isWhiteSpace(line.charAt(i)) && i < line.length) {
      i++;
    }
    if (i === line.length || line.charAt(i) === '%') {
      return;

    }
    // Start with the standard staff, clef and key symbols on each line
    var delayStartNewLine = multilineVars.start_new_line;
    if (multilineVars.continueall === undefined)
      multilineVars.start_new_line = true;
    else
      multilineVars.start_new_line = false;
    var tripletNotesLeft = 0;

    // See if the line starts with a header field
    var retHeader = header.letter_to_body_header(line, i);
    if (retHeader[0] > 0) {
      i += retHeader[0];
      // TODO-PER: Handle inline headers
    }
    var el = { };

    while (i < line.length)
    {
      var startI = i;
      if (line.charAt(i) === '%')
        break;

      var retInlineHeader = header.letter_to_inline_header(line, i);
      if (retInlineHeader[0] > 0) {
        i += retInlineHeader[0];
        // TODO-PER: Handle inline headers
        //multilineVars.start_new_line = false;
      } else {
        // Wait until here to actually start the line because we know we're past the inline statements.
        if (delayStartNewLine) {
          startNewLine();
          delayStartNewLine = false;
        }

        // We need to decide if the following characters are a bar-marking or a note-group.
        // Unfortunately, that is ambiguous. Both can contain chord symbols and decorations.
        // If there is a grace note either before or after the chord symbols and decorations, then it is definitely a note-group.
        // If there is a bar marker, it is definitely a bar-marking.
        // If there is either a core-note or chord, it is definitely a note-group.
        // So, loop while we find grace-notes, chords-symbols, or decorations. [It is an error to have more than one grace-note group in a row; the others can be multiple]
        // Then, if there is a grace-note, we know where to go.
        // Else see if we have a chord, core-note, slur, triplet, or bar.

        var ret;
        while (1) {
          ret = tokenizer.eatWhiteSpace(line, i);
          if (ret > 0) {
            i += ret;
          }
          if (i > 0 && line.charAt(i-1) === '\x12') {
            // there is one case where a line continuation isn't the same as being on the same line, and that is if the next character after it is a header.
            ret = header.letter_to_body_header(line, i);
            if (ret[0] > 0) {
              // TODO: insert header here
              i = ret[0];
              multilineVars.start_new_line = false;
            }
          }
          // gather all the grace notes, chord symbols and decorations
          ret = letter_to_spacer(line, i);
          if (ret[0] > 0) {
            i += ret[0];
          }

          ret = letter_to_chord(line, i);
          if (ret[0] > 0) {
            // There could be more than one chord here if they have different positions.
            // If two chords have the same position, then connect them with newline.
            if (!el.chord)
              el.chord = [];
            var chordName = tokenizer.translateString(ret[1]);
            chordName = chordName.replace(/;/g, "\n");
            var addedChord = false;
            for (var ci = 0; ci < el.chord.length; ci++) {
              if (el.chord[ci].position === ret[2]) {
                addedChord = true;
                el.chord[ci].name += "\n" + chordName;
              }
            }
            if (addedChord === false) {
              if (ret[2] === null && ret[3])
                el.chord.push({name: chordName, rel_position: ret[3]});
              else
                el.chord.push({name: chordName, position: ret[2]});
            }

            i += ret[0];
            var ii = tokenizer.skipWhiteSpace(line.substring(i));
            if (ii > 0)
              el.force_end_beam_last = true;
            i += ii;
          } else {
            if (nonDecorations.indexOf(line.charAt(i)) === -1)
              ret = letter_to_accent(line, i);
            else ret = [ 0 ];
            if (ret[0] > 0) {
              if (ret[1] === null) {
                if (i + 1 < line.length)
                  startNewLine();	// There was a ! in the middle of the line. Start a new line if there is anything after it.
              } else if (ret[1].length > 0) {
                if (ret[1].indexOf("style=") === 0) {
                  el.style = ret[1].substr(6);
                } else {
                  if (el.decoration === undefined)
                    el.decoration = [];
                  el.decoration.push(ret[1]);
                }
              }
              i += ret[0];
            } else {
              ret = letter_to_grace(line, i);
              // TODO-PER: Be sure there aren't already grace notes defined. That is an error.
              if (ret[0] > 0) {
                el.gracenotes = ret[1];
                i += ret[0];
              } else
                break;
            }
          }
        }

        ret = letter_to_bar(line, i);
        if (ret[0] > 0) {
          // This is definitely a bar
          if (el.gracenotes !== undefined) {
            // Attach the grace note to an invisible note
            el.rest = { type: 'spacer' };
            el.duration = 0.125; // TODO-PER: I don't think the duration of this matters much, but figure out if it does.
            multilineVars.addFormattingOptions(el, tune.formatting, 'note');
            tune.appendElement('note', startOfLine+i, startOfLine+i+ret[0], el);
            multilineVars.measureNotEmpty = true;
            el = {};
          }
          var bar = {type: ret[1]};
          if (bar.type.length === 0)
            warn("Unknown bar type", line, i);
          else {
            if (multilineVars.inEnding && bar.type !== 'bar_thin') {
              bar.endEnding = true;
              multilineVars.inEnding = false;
            }
            if (ret[2]) {
              bar.startEnding = ret[2];
              if (multilineVars.inEnding)
                bar.endEnding = true;
              multilineVars.inEnding = true;
            }
            if (el.decoration !== undefined)
              bar.decoration = el.decoration;
            if (el.chord !== undefined)
              bar.chord = el.chord;
            if (bar.startEnding && multilineVars.barFirstEndingNum === undefined)
              multilineVars.barFirstEndingNum = multilineVars.currBarNumber;
            else if (bar.startEnding && bar.endEnding && multilineVars.barFirstEndingNum)
              multilineVars.currBarNumber = multilineVars.barFirstEndingNum;
            else if (bar.endEnding)
              multilineVars.barFirstEndingNum = undefined;
            if (bar.type !== 'bar_invisible' && multilineVars.measureNotEmpty) {
              multilineVars.currBarNumber++;
              if (multilineVars.barNumbers && multilineVars.currBarNumber % multilineVars.barNumbers === 0)
                multilineVars.barNumOnNextNote = multilineVars.currBarNumber;
            }
            multilineVars.addFormattingOptions(el, tune.formatting, 'bar');
            tune.appendElement('bar', startOfLine+i, startOfLine+i+ret[0], bar);
            multilineVars.measureNotEmpty = false;
            el = {};
          }
          i += ret[0];
        } else if (line[i] === '&') {	// backtrack to beginning of measure
          warn("Overlay not yet supported", line, i);
          i++;

        } else {
          // This is definitely a note group
          //
          // Look for as many open slurs and triplets as there are. (Note: only the first triplet is valid.)
          ret = letter_to_open_slurs_and_triplets(line, i);
          if (ret.consumed > 0) {
            if (ret.startSlur !== undefined)
              el.startSlur = ret.startSlur;
            if (ret.triplet !== undefined) {
              if (tripletNotesLeft > 0)
                warn("Can't nest triplets", line, i);
              else {
                el.startTriplet = ret.triplet;
                tripletNotesLeft = ret.num_notes === undefined ? ret.triplet : ret.num_notes;
              }
            }
            i += ret.consumed;
          }

          // handle chords.
          if (line.charAt(i) === '[') {
            var chordStartChar = i;
            i++;
            var chordDuration = null;

            var done = false;
            while (!done) {
              var chordNote = getCoreNote(line, i, {}, false);
              if (chordNote !== null) {
                if (chordNote.end_beam) {
                  el.end_beam = true;
                  delete chordNote.end_beam;
                }
                if (el.pitches === undefined) {
                  el.duration = chordNote.duration;
                  el.pitches = [ chordNote ];
                } else	// Just ignore the note lengths of all but the first note. The standard isn't clear here, but this seems less confusing.
                  el.pitches.push(chordNote);
                delete chordNote.duration;

                if (multilineVars.inTieChord[el.pitches.length]) {
                  chordNote.endTie = true;
                  multilineVars.inTieChord[el.pitches.length] = undefined;
                }
                if (chordNote.startTie)
                  multilineVars.inTieChord[el.pitches.length] = true;

                i  = chordNote.endChar;
                delete chordNote.endChar;
              } else if (line.charAt(i) === ' ') {
                // Spaces are not allowed in chords, but we can recover from it by ignoring it.
                warn("Spaces are not allowed in chords", line, i);
                i++;
              } else {
                if (i < line.length && line.charAt(i) === ']') {
                  // consume the close bracket
                  i++;

                  if (multilineVars.next_note_duration !== 0) {
                    el.duration = el.duration * multilineVars.next_note_duration;
                    multilineVars.next_note_duration = 0;
                  }

                  if (multilineVars.inTie) {
                    Common.each(el.pitches, function(pitch) { pitch.endTie = true; });
                    multilineVars.inTie = false;
                  }

                  if (tripletNotesLeft > 0) {
                    tripletNotesLeft--;
                    if (tripletNotesLeft === 0) {
                      el.endTriplet = true;
                    }
                  }

                  var postChordDone = false;
                  while (i < line.length && !postChordDone) {
                    switch (line.charAt(i)) {
                      case ' ':
                      case '\t':
                        addEndBeam(el);
                        break;
                      case ')':
                        if (el.endSlur === undefined) el.endSlur = 1; else el.endSlur++;
                        break;
                      case '-':
                        Common.each(el.pitches, function(pitch) { pitch.startTie = {}; });
                        multilineVars.inTie = true;
                        break;
                      case '>':
                      case '<':
                        var br2 = getBrokenRhythm(line, i);
                        i += br2[0] - 1;	// index gets incremented below, so we'll let that happen
                        multilineVars.next_note_duration = br2[2];
                        if (chordDuration)
                          chordDuration = chordDuration * br2[1];
                        else
                          chordDuration = br2[1];
                        break;
                      case '1':
                      case '2':
                      case '3':
                      case '4':
                      case '5':
                      case '6':
                      case '7':
                      case '8':
                      case '9':
                      case '/':
                        var fraction = tokenizer.getFraction(line, i);
                        chordDuration = fraction.value;
                        i = fraction.index;
                        if (line.charAt(i) === '-' || line.charAt(i) === ')' || line.charAt(i) === ' ' || line.charAt(i) === '<' || line.charAt(i) === '>')
                          i--; // Subtracting one because one is automatically added below
                        else
                          postChordDone = true;
                        break;
                      default:
                        postChordDone = true;
                        break;
                    }
                    if (!postChordDone) {
                      i++;
                    }
                  }
                } else
                  warn("Expected ']' to end the chords", line, i);

                if (el.pitches !== undefined) {
                  if (chordDuration !== null) {
                    el.duration = el.duration * chordDuration;
                  }
                  if (multilineVars.barNumOnNextNote) {
                    el.barNumber = multilineVars.barNumOnNextNote;
                    multilineVars.barNumOnNextNote = null;
                  }
                  multilineVars.addFormattingOptions(el, tune.formatting, 'note');
                  tune.appendElement('note', startOfLine+chordStartChar, startOfLine+i, el);
                  multilineVars.measureNotEmpty = true;
                  el = {};
                }
                done = true;
              }
            }

          } else {
            // Single pitch
            var el2 = {};
            var core = getCoreNote(line, i, el2, true);
            if (el2.endTie !== undefined) multilineVars.inTie = true;
            if (core !== null) {
              if (core.pitch !== undefined) {
                el.pitches = [ { } ];
                // TODO-PER: straighten this out so there is not so much copying: getCoreNote shouldn't change e'
                if (core.accidental !== undefined) el.pitches[0].accidental = core.accidental;
                el.pitches[0].pitch = core.pitch;
                if (core.endSlur !== undefined) el.pitches[0].endSlur = core.endSlur;
                if (core.endTie !== undefined) el.pitches[0].endTie = core.endTie;
                if (core.startSlur !== undefined) el.pitches[0].startSlur = core.startSlur;
                if (el.startSlur !== undefined) el.pitches[0].startSlur = el.startSlur;
                if (core.startTie !== undefined) el.pitches[0].startTie = core.startTie;
                if (el.startTie !== undefined) el.pitches[0].startTie = el.startTie;
              } else {
                el.rest = core.rest;
                if (core.endSlur !== undefined) el.endSlur = core.endSlur;
                if (core.endTie !== undefined) el.rest.endTie = core.endTie;
                if (core.startSlur !== undefined) el.startSlur = core.startSlur;
                if (core.startTie !== undefined) el.rest.startTie = core.startTie;
                if (el.startTie !== undefined) el.rest.startTie = el.startTie;
              }

              if (core.chord !== undefined) el.chord = core.chord;
              if (core.duration !== undefined) el.duration = core.duration;
              if (core.decoration !== undefined) el.decoration = core.decoration;
              if (core.graceNotes !== undefined) el.graceNotes = core.graceNotes;
              delete el.startSlur;
              if (multilineVars.inTie) {
                if (el.pitches !== undefined) {
                  el.pitches[0].endTie = true;
                  multilineVars.inTie = false;
                } else if (el.rest.type !== 'spacer') {
                  el.rest.endTie = true;
                  multilineVars.inTie = false;
                }
              }
              if (core.startTie || el.startTie)
                multilineVars.inTie = true;
              i  = core.endChar;

              if (tripletNotesLeft > 0) {
                tripletNotesLeft--;
                if (tripletNotesLeft === 0) {
                  el.endTriplet = true;
                }
              }

              if (core.end_beam)
                addEndBeam(el);

              // If there is a whole rest, then it should be the duration of the measure, not it's own duration. We need to special case it.
              if (el.rest && el.rest.type === 'rest' && el.duration === 1) {
                el.rest.type = 'whole';

                el.duration = durationOfMeasure(multilineVars);
              }

              if (multilineVars.barNumOnNextNote) {
                el.barNumber = multilineVars.barNumOnNextNote;
                multilineVars.barNumOnNextNote = null;
              }
              multilineVars.addFormattingOptions(el, tune.formatting, 'note');
              tune.appendElement('note', startOfLine+startI, startOfLine+i, el);
              multilineVars.measureNotEmpty = true;
              el = {};
            }
          }

          if (i === startI) {	// don't know what this is, so ignore it.
            if (line.charAt(i) !== ' ' && line.charAt(i) !== '`')
              warn("Unknown character ignored", line, i);
            i++;
          }
        }
      }
    }
  }
413538
private void commentLinesAfter( String content, int line )
  {
    int offset = _root.getElement( line ).getEndOffset();
    // End of comment not found, nothing to do
    int endDelimiter = indexOf( content, getEndDelimiter(), offset );
    if( endDelimiter < 0 )
    {
      return;
    }
    // Matching start/end of comment found, comment the lines
    int startDelimiter = lastIndexOf( content, getStartDelimiter(), endDelimiter );
    if( startDelimiter < 0 || startDelimiter <= offset )
    {
      setCharacterAttributes( offset, endDelimiter - offset + 1, _comment, false );
    }
  }
494250
private boolean isComment(String line) {
        String trimmed = line.trim();
        if (trimmed.length() == 0) {
            return false;
        }
        return trimmed.charAt(0) == '#';
    }
457818
protected boolean isLevelInitialContentLine(String line) {
        final Matcher matcher = LEVEL_INITIAL_CONTENT_PATTERN.matcher(line.trim().toUpperCase(Locale.ENGLISH));
        return matcher.find();
    }
1214281
public void setBreakPoint(int line) {
        if (sourceInfo.breakableLine(line)) {
            boolean changed = sourceInfo.breakpoint(line, true);
            if (changed) {
                fileHeader.repaint();
            }
        }
    }
78695
private static String getClassFromLine(String line) {
        line = line.trim();

        // Skip commented lines
        if (line.length() == 0 || line.startsWith("#"))
            return null;

        // lop off spaces/tabs/end-of-line-comments
        String[] className = line.split("[\\s#]");

        if (className.length >= 1)
            return className[0];

        return null;
    }