class LineCursor {
        private URI uri;
        private long lineNumber;
        private String line;
        private IOException failure;

        public LineCursor() {
        }

        public LineCursor(URI uri, long lineNumber, @Nullable String line, @Nullable IOException failure) {
            this.uri = uri;
            this.lineNumber = lineNumber;
            this.line = line;
            this.failure = failure;
        }

        public URI uri() {
            return uri;
        }

        public long lineNumber() {
            return lineNumber;
        }

        @Nullable
        public String line() {
            return line;
        }

        @Nullable
        public IOException failure() {
            return failure;
        }

        @VisibleForTesting
        public LineCursor copy() {
            return new LineCursor(uri, lineNumber, line, failure);
        }

        @Override
        public String toString() {
            return "LineCursor{" + uri + ":" + lineNumber + ":line=" + line + ", failure=" + failure + "}";
        }

        @Override
        public int hashCode() {
            return Objects.hash(uri, lineNumber, line, failure);
        }

        @Override
        public boolean equals(Object obj) {<FILL_FUNCTION_BODY>}
    }

            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            LineCursor other = (LineCursor) obj;
            return Objects.equals(uri, other.uri)
                && lineNumber == other.lineNumber
                && Objects.equals(line, other.line)
                && Objects.equals(failure, other.failure);
        
<no_super_class>