<commit_before>function State(params) {
    var state;

    if (this instanceof State) {
        state = this;
    } else {
        state = createObject(State.prototype);
    }

    state._init(params);

    return state;
}

State.prototype = {
    constructor: State,

    _init: function(params) {
        this._params = this._path2object(this._getHash()) || {};

        this.set(params);
    },

    /**
     * Converts slash-slpitted key-value path to object
     *
     * @param {String} path The path (Like: key1/value1/key2/value2)
     *
     * @returns {Object} Object
     */
    _path2object: function(path) {
        var object = {},
            pathParts = path.split('/');

        if (pathParts.length > 1) {
            var key,
                value;

            for (var i = 1; i < pathParts.length; i+=2) {
                key = pathParts[i];
                value = pathParts[i + 1];

                if (key.length) {
                    object[key] = decodeURIComponent(value);
                }
            }
        }

        return object;
    },

    /**
     * Converts object to key-value path
     *
     * @param {String} path The path (Like: key1/value1/key2/value2)
     *
     * @returns {Object} Object
     */
    _object2path: function(object) {
        var path = '!';

        for (var key in object) {
            path = path + '/' + encodeURIComponent(key) + '/' + encodeURIComponent(object[key]);
        }

        return path;
    },

    /**
     * Sets page location hash
     *
     * @param {String} hash
     */
    _setHash: function(hash) {
        window.location.hash = hash;
    },

    /**
     * Returns page location hash
     *
     * @returns {String} The hash string
     */
    _getHash: function() {
        var hash = window.location.hash;

        if (hash.length) {
            return hash.split('!')[1];
        }

        return '';
    },

    /**
     * Sets state
     *
     * @param {Object} params 
     *
     * @returns {Object} State object
     *
     */
    set: function(params) {
        _.assign(this._params, params);

        this._setHash(this._object2path(this._params));

        return this._params;
    },

    /**
     * Returns state value by a key
     *
     * @param {[String]} key The key
     *<commit_msg>State now listen location changes<commit_after>function State(params) {
    var state;

    if (this instanceof State) {
        state = this;
    } else {
        state = createObject(State.prototype);
    }

    state._init(params);

    return state;
}

State.prototype = {
    constructor: State,

    _init: function(params) {
        this._params = this._path2object(this._getHash()) || {};

        this._bindListeners();

        this.set(params);
    },

    _bindListeners: function() {
        var state = this,

            onhashchangeHandler = window.onhashchange;

        window.onhashchange = function() {
            if (onhashchangeHandler instanceof Function) {
                onhashchangeHandler.call(window);
            }

            state.set(state._path2object(state._getHash()));
        };
    },

    /**
     * Converts slash-slpitted key-value path to object
     *
     * @param {String} path The path (Like: key1/value1/key2/value2)
     *
     * @returns {Object} Object
     */
    _path2object: function(path) {
        var object = {},
            pathParts = path.split('/');

        if (pathParts.length > 1) {
            var key,
                value;

            for (var i = 1; i < pathParts.length; i+=2) {
                key = pathParts[i];
                value = pathParts[i + 1];

                if (key.length) {
                    object[key] = decodeURIComponent(value);
                }
            }
        }

        return object;
    },

    /**
     * Converts object to key-value path
     *
     * @param {String} path The path (Like: key1/value1/key2/value2)
     *
     * @returns {Object} Object
     */
    _object2path: function(object) {
        var path = '!';

        for (var key in object) {
            path = path + '/' + encodeURIComponent(key) + '/' + encodeURIComponent(object[key]);
        }

        return path;
    },

    /**
     * Sets page location hash
     *
     * @param {String} hash
     */
    _setHash: function(hash) {
        window.location.hash = hash;
    },

    /**
     * Returns page location hash
     *
     * @returns {String} The hash string
     */
    _getHash: function() {
        var hash = window.location.hash;

        if (hash.length) {
            return hash.split('!')[1];
        }

        return '';
    },

    /**
     * Sets state according to `params`
     *
     * @param {Object} params Key-value object
     *
     * @returns {Object} State object
     *
     */
    set: function(params) {
        _.assign(this._params, params);

        this._setHash(this._object2path(this._params));

        return this._params;
    },

    /**
     * Returns state value by a key
     *
     * @param {[String]} key The key
     *
{'fraction_non_alphanumeric': 0.12828622257363115, 'fraction_numerical': 0.00691836331290769, 'mean_word_length': 1.577687213448803, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5351750', 'n_tokens_mistral': 1543, 'n_tokens_neox': 1487, 'n_words': 339}