<commit_before>import device from "./device.js";
import * as event from "./event.js";

/**
 * allow to access and manage the device localStorage
 * @example
 * // Initialize "score" and "lives" with default values
 * // This loads the properties from localStorage if they exist, else it sets the given defaults
 * me.save.add({ score : 0, lives : 3 });
 *
 * // Print all
 * // On first load, this prints { score : 0, lives : 3 }
 * // On further reloads, it prints { score : 31337, lives : 3, complexObject : ... }
 * // Because the following changes will be saved to localStorage
 * console.log(JSON.stringify(me.save));
 *
 * // Save score
 * me.save.score = 31337;
 *
 * // Also supports complex objects thanks to the JSON backend
 * me.save.add({ complexObject : {} })
 * me.save.complexObject = { a : "b", c : [ 1, 2, 3, "d" ], e : { f : [{}] } };
 *
 * // WARNING: Do not set any child properties of complex objects directly!
 * // Changes made that way will not save. Always set the entire object value at once.
 * // If you cannot live with this limitation, there's a workaround:
 * me.save.complexObject.c.push("foo"); // Modify a child property
 * me.save.complexObject = me.save.complexObject; // Save the entire object!
 *
 * // Remove "lives" from localStorage
 * me.save.remove("lives");
 * @namespace save
 */

 // Variable to hold the object data
 var data = {};

 /**
  * a function to check if the given key is a reserved word
  * @ignore
  */
 function isReserved(key) {
     return (key === "add" || key === "remove");
 }


// Initialize me.save on Boot event
event.on(event.BOOT, () => {
    // Load previous data if local Storage is supported
    if (typeof globalThis.localStorage !== "undefined") {
        var me_save_content = globalThis.localStorage.getItem("me.save");

        if (typeof me_save_content === "string" && me_save_content.length > 0) {
            var keys = JSON.parse(me_save_content) || [];
            keys.forEach(function (key) {
                data[key] = JSON.parse(globalThis.localStorage.getItem("me.save." + key));
            });
        }
    }
});

var save = {

    /**
     * Add new keys to localStorage and set them to the given default values if they do not exist
     * @name add
     * @memberof save
     * @param {object} props key and corresponding values
     * @example
     * // Initialize "score" and "lives" with default values
     * me.save.add({ score : 0, lives : 3 });
     * // get or set the value through me.save
     * me.save.score = 1000;
     */
    add(props) {
        var obj = save;

        Object.keys(props).forEach(function (key) {
            if (isReserved(key)) {
                return;
            }

            (function (prop) {
                Object.defineProperty(obj, prop, {
                    configurable : true,
                    enumerable : true,
                    /**
                     * @ignore
                     */
                    get () {
                        return data[prop];
                    },
                    /**
                     * @ignore
                     */
                    set (value) {
                        data[prop] = value;
                        if (device.localStorage === true) {
                            globalThis.localStorage.setItem("me.save." + prop, JSON.stringify(value));
                        }
                    }
                });
            })(key);

            // Set default value for key
            if (!(key in data)) {
                obj[key] = props[key];
            }
        });

        // Save keys
        if (device.localStorage === true) {
            globalThis.localStorage.setItem("me.save", JSON.stringify(Object.keys(data)));
        }
    },

    /**
     * Remove a key from localStorage
     * @name remove
     * @memberof save
     * @param {string} key key to be removed
     * @example
     * // Remove the "score" key from localStorage
     * me.save.remove("score");
     */
    remove (key) {
        if (!isReserved(key)) {
            if (typeof data[key] !== "undefined") {
                delete data[key];
                if (device.localStorage === true) {
                    globalThis.localStorage.removeItem("me.save." + key);
                    globalThis.localStorage.setItem("me.save", JSON.stringify(Object.keys(data)));
                }
            }
        }
    }
};

export default save;<commit_msg>fix cyclic dependency between device and save<commit_after>import * as event from "./event.js";

/**
 * allow to access and manage the device localStorage
 * @example
 * // Initialize "score" and "lives" with default values
 * // This loads the properties from localStorage if they exist, else it sets the given defaults
 * me.save.add({ score : 0, lives : 3 });
 *
 * // Print all
 * // On first load, this prints { score : 0, lives : 3 }
 * // On further reloads, it prints { score : 31337, lives : 3, complexObject : ... }
 * // Because the following changes will be saved to localStorage
 * console.log(JSON.stringify(me.save));
 *
 * // Save score
 * me.save.score = 31337;
 *
 * // Also supports complex objects thanks to the JSON backend
 * me.save.add({ complexObject : {} })
 * me.save.complexObject = { a : "b", c : [ 1, 2, 3, "d" ], e : { f : [{}] } };
 *
 * // WARNING: Do not set any child properties of complex objects directly!
 * // Changes made that way will not save. Always set the entire object value at once.
 * // If you cannot live with this limitation, there's a workaround:
 * me.save.complexObject.c.push("foo"); // Modify a child property
 * me.save.complexObject = me.save.complexObject; // Save the entire object!
 *
 * // Remove "lives" from localStorage
 * me.save.remove("lives");
 * @namespace save
 */

 // Variable to hold the object data
 var data = {};

 /**
  * a function to check if the given key is a reserved word
  * @ignore
  */
 function isReserved(key) {
     return (key === "add" || key === "remove");
 }


// Initialize me.save on Boot event
event.on(event.BOOT, () => {
    // Load previous data if local Storage is supported
    if (typeof globalThis.localStorage !== "undefined") {
        var me_save_content = globalThis.localStorage.getItem("me.save");

        if (typeof me_save_content === "string" && me_save_content.length > 0) {
            var keys = JSON.parse(me_save_content) || [];
            keys.forEach(function (key) {
                data[key] = JSON.parse(globalThis.localStorage.getItem("me.save." + key));
            });
        }
    }
});

var save = {

    /**
     * Add new keys to localStorage and set them to the given default values if they do not exist
     * @name add
     * @memberof save
     * @param {object} props key and corresponding values
     * @example
     * // Initialize "score" and "lives" with default values
     * me.save.add({ score : 0, lives : 3 });
     * // get or set the value through me.save
     * me.save.score = 1000;
     */
    add(props) {
        var obj = save;

        Object.keys(props).forEach(function (key) {
            if (isReserved(key)) {
                return;
            }

            (function (prop) {
                Object.defineProperty(obj, prop, {
                    configurable : true,
                    enumerable : true,
                    /**
                     * @ignore
                     */
                    get () {
                        return data[prop];
                    },
                    /**
                     * @ignore
                     */
                    set (value) {
                        data[prop] = value;
                        if (globalThis.localStorage === true) {
                            globalThis.localStorage.setItem("me.save." + prop, JSON.stringify(value));
                        }
                    }
                });
            })(key);

            // Set default value for key
            if (!(key in data)) {
                obj[key] = props[key];
            }
        });

        // Save keys
        if (globalThis.localStorage === true) {
            globalThis.localStorage.setItem("me.save", JSON.stringify(Object.keys(data)));
        }
    },

    /**
     * Remove a key from localStorage
     * @name remove
     * @memberof save
     * @param {string} key key to be removed
     * @example
     * // Remove the "score" key from localStorage
     * me.save.remove("score");
     */
    remove (key) {
        if (!isReserved(key)) {
            if (typeof data[key] !== "undefined") {
                delete data[key];
                if (globalThis.localStorage === true) {
                    globalThis.localStorage.removeItem("me.save." + key);
                    globalThis.localStorage.setItem("me.save", JSON.stringify(Object.keys(data)));
                }
            }
        }
    }
};

export default save;
{'fraction_non_alphanumeric': 0.1293800539083558, 'fraction_numerical': 0.005615453728661276, 'mean_word_length': 1.6968503937007875, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '873743', 'n_tokens_mistral': 2494, 'n_tokens_neox': 2367, 'n_words': 735}