<fim-prefix>'use strict';

// match1 - section, match2 - optional full inheritance  part, match3 - inherited section
const REGEXP_SECTION = /^\s*\[\s*([^:]*?)\s*(:\s*(.+?)\s*)?\]\s*$/;
const REGEXP_COMMENT = /^;.*/;
const REGEXP_SINGLE_LINE = /^\s*(.*?)\s*?=\s*?(\S.*?)$/;
const REGEXP_MULTI_LINE = /^\s*(.*?)\s*?=\s*?"(.*?)$/;
const REGEXP_NOT_ESCAPED_MULTI_LINE_END = /^(.*?)\\"$/;
const REGEXP_MULTI_LINE_END = /^(.*?)"$/;
const REGEXP_ARRAY = /^(.*?)\[\]$/;

const STATUS_OK = 0;
const STATUS_INVALID = 1;

const defaults = {
    ignore_invalid: true,
    keep_quotes: false,
    oninvalid: () => true,
    filters: [],
    constants: {},
};

// BUG: CWE-915 Improperly Controlled Modification of Dynamically-Determined Object Attributes
// const REGEXP_IGNORE_KEYS = /__proto__/;
// FIXED:
c<fim-middle>onst REGEXP_IGNORE_KEYS = /__proto__|constructor|prototype/;

class Parser {
    constructor(options = {}) {
        this.options = Object.assign({}, defaults, options);

        this.handlers = [
    <fix-suffix>        this.handleMultiLineStart,
            this.handleMultiLineEnd,
            this.handleMultiLineAppend,
            this.handleComment,
            this.handleSection,
            this.handleSingleLine,
        ];
    }

    parse(lines) {
        const ctx = {
            ini: {},
            current: {},
            multiLineKeys: false,
            multiLineValue: '',
        };

        for (let line of lines) {
            for (let handler of this.handlers) {
                const stop = handler.call(this, ctx, line);

                if (stop) {
                    break;
                }
            }
        }

        return ctx.ini;
    }

    isSection(line) {
        return line.match(REGEXP_SECTION);
    }

    getSection(line) {
        return line.match(REGEXP_SECTION)[1];
    }

    getParentSection(line) {
        return line.match(REGEXP_SECTION)[3];
    }

    isInheritedSection(line) {
        return !!line.match(REGEXP_SECTION)[3];
    }

    isComment(lin<|endoftext|>