<commit_before>//console.log("Running backbone agent");

window.__backboneAgent = new (function() {

    // Imposta il this nella funzione func pari all'oggetto scope.
    var bind = function(func, scope) {
        return function() {
            return func.apply(scope, arguments);
        }
    }

    // @private
    // Azione di un componente dell'app.
    var AppComponentAction = function(type, name, target, targetKind) {
        
        this.timestamp = Date.now();
        this.type = type; // stringa
        this.name = name; // stringa
        this.target = target; // oggetto
        this.targetKind = targetKind || "Other"; // può essere "AppComponent", "jQuery Event" o "Other"
        
        //// Metodi di utilità ////
         
        // stampa nella console le informazioni sull'azione
        this.printDetailsInConsole = function() {
        }
    }

    // @private
    var AppComponentInfo = function(category, index, component, actions) {

        // nome del componente Backbone di cui questo componente dell'app è un discendente.
        // I valori validi sono "View", "Model", "Collection", "Router"
        this.category = category;
        // usato come identificatore tra tutti i componenti dell'app della sua categoria
        this.index = index;

        this.component = component; // oggetto
        this.actions = actions || []; // array di oggetti AppComponentAction
    } 
        
    // @private
    // All'atto dell'istanziazione di un componente, l'agent gli assegna
    // un indice che lo identifica all'interno dei vari array
    // riguardanti i componenti di quella categoria.
    // Tale indice viene calcolato incrementando quello dell'ultimo componente
    // della propria categoria.
    var lastAppComponentsIndex = {
        "View": -1,
        "Model": -1,
        "Collection": -1,
        "Router": -1
    };

    //// API PUBBLICA ////
    
    // Informazioni sui componenti dell'applicazione.
    // Hash <"componentCategory", [AppComponentInfo]>.
    // (Gli indici degli array sono quelli dei componenti.)
    this.appComponentsInfo = {
        "View": [],
        "Model": [],
        "Collection": [],
        "Router": []
    };

    // Restituisce un array con gli indici dei componenti dell'applicazione
    // della categoria specificata che sono presenti nell'app.
    this.getAppComponentsIndexes = bind(function(appComponentCategory) {
        var appComponentsInfo = this.appComponentsInfo[appComponentCategory];

        var appComponentsIndexes = [];
        for (var appComponentIndex in appComponentsInfo) {
            if (appComponentsInfo.hasOwnProperty(appComponentIndex)) {
                appComponentsIndexes.push(appComponentIndex);
            }
        }
        return appComponentsIndexes;
    }, this);
    
    // Restituisce l'oggetto di tipo AppComponentInfo con le informazioni sul componente dell'app passato
    // o undefined se l'oggetto passato non è un componente valido.
    this.getAppComponentInfo = bind(function(appComponent) {
        return getHiddenProperty(appComponent, "appComponentInfo");
    }, this);

    this.getAppComponentInfoByIndex = bind(function(appComponentCategory, appComponentIndex) {
        var appComponentInfo = this.appComponentsInfo[appComponentCategory][appComponentIndex];
        return appComponentInfo;
    }, this);

    // Restituisce l'info della vista a cui appartiene l'elemento html passato, o undefined se non esiste.
    // L'elemento appartiene alla vista se questo combacia perfettamente con la sua proprietà el, o 
    // se questa è l'ascendente più vicino rispetto a tutte le altre viste.
    this.getAppViewInfoFromElement = bind(function(pageElement) {
        // funzione che controlla se l'elemento html target è un ascendente dell'elemento html of
        var isAscendant = function(target, of) {
            if (!of) return false;

            var ofParent = of.parentNode;
            if (target === ofParent) return true;
            return isAscendant(target, ofParent);
        }

        // cerca il miglior candidato
        var candidateViewInfo = undefined;
        var viewsIndexes = this.getAppComponentsIndexes("View");
        for (var i=0,l=viewsIndexes.length; i<l; i++) {
            var currentViewInfo = this.getAppComponentInfoByIndex("View", viewsIndexes[i]);
            var currentView = currentViewInfo.component;

            if (currentView.el === pageElement) {
                // candidato perfetto trovato
                candidateViewInfo = currentViewInfo;
                break;
            }
            // l'el di currentView è un ascendente di pageElement ed è un discendente del miglior
            // candidato trovato finora?
            var candidateView = candidateViewInfo? candidateViewInfo.component : undefined;
            var isBetterCandidate = isAscendant(currentView.el, pageElement) &&
                                   (!candidateView || isAscendant(candidateView.el, currentView.el));
            if (isBetterCandidate) {
                // candidato migliore trovato
                candidateViewInfo = currentViewInfo;
            }
        }
        return candidateViewInfo;
    }, this);
    
    //// PARTE COMPLETAMENTE PRIVATA ////

    // @private
	var watchOnce = function(object, property, callback) {
		watch(object, property, function onceHandler(prop, action, newvalue, oldvalue) {
			// facendo l'unwatch prima di chiamare la callback (invece di farlo dopo),
			// è possibile in quest'ultima impostare la proprietà property 
			// senza incorrere in un loop infinito.
			unwatch(object, property, onceHandler);

			callback(prop, action, newvalue, oldvalue);		
		});
	}

    // @private
    // Esegue la callback ogni volta che viene settata la proprietà property sull'oggetto object
    var onSetted = function(object, property, callback) {
		watch(object, property, function(prop, action, difference, oldvalue) {
			if (action == "set") { callback(); }
		}, 0);
    }

    // @private
    // Come la onSetted, ma la callback viene chiamata solo LA PRIMA VOLTA che la proprietà è settata.
    var onceSetted = function(object, property, callback) {
		watchOnce(object, property, function(prop, action, difference, oldvalue) {
			if (action == "set") { callback(); }
		}, 0);
    }

    // @private
    // Utilizza le librerie watch.js e Object.observe.poly.js per monitorare i set
    // della proprietà property di object e delle sue sottoproprietà, comprese quelle che
    // non sono presenti all'avvio del watching in quanto aggiunte successivamente.
    // Il livello di profondità del watching è specificato da recursionLevel (come in watch.js):
    // undefined => ricorsione completa, 0 => no ricorsione (solo il livello 0), n>0 => dal livello 0 al livello n)
    var onSettedDeep = function(object, property, onChange, recursionLevel) {

        // funzione per monitorare le sottoproprietà, esistenti e aggiunte successivamente
        var handleSubProperties = function(parentObject) {
            if (recursionLevel !== 0 && typeof parentObject == "object") {
                var subRecursionLevel = (recursionLevel===undefined)? recursionLevel : recursionLevel-1;

                // monitora le sottoproprietà esistenti
                for (var subProperty in parentObject) {
                    if (parentObject.hasOwnProperty(subProperty)) {
                        onSettedDeep(parentObject, subProperty, onChange, subRecursionLevel);
                    }
                }

                // monitora le sottoproprietà aggiunte successivamente
                Object.observe(object[property], function(updates) {
                    for (var i=0,l=updates.length; i<l; i++) {
                        var update = updates[i];
                        var subProperty = update.name;

                        if (update.type == "new") { // nuova sottoproprietà
                            onSettedDeep(parentObject, subProperty, onChange, subRecursionLevel);

                            onChange();
                        }
                    } 
                });
            }
        }

        // monitora i set della property
        onSetted(object, property, function() {
            // monitora i set per le sottoproprietà del nuovo (eventuale) oggetto settato
            handleSubProperties(object[property]);
            
            onChange(); 
        });

        // monitora i set delle sottoproprietà
        handleSubProperties(object[property]);
    }

    // @private
    // Sostituisce la funzione functionName di object con quella restituita dalla funzione patcher.
    // La funzione patcher viene chiamata con la funzione originale come argomento.
    var patchFunction = function(object, functionName, patcher) {
    	var originalFunction = object[functionName];
    	object[functionName] = patcher(originalFunction);
    }

    // @private
    // Come patchFunction, ma aspetta che il metodo sia settato se questo è undefined al momento
    // della chiamata.
    var patchFunctionLater = function(object, functionName, patcher) {
        if (object[functionName] === undefined) {
            onceSetted(object, functionName, function() {
                patchFunction(object, functionName, patcher);
            });
        } else {
            patchFunction(object, functionName, patcher);
        }
    }

    // @private
    var isArray = function(object) {
        return Object.prototype.toString.call(object) == '[object Array]';
    }

    // @private
    // Restituisce un clone dell'oggetto passato.
    // N.B: le sottoproprietà non saranno clonate (shallow clone).
    var clone = function(object) {
        if (typeof object != "object") return object;
        if (isArray(object)) return object.slice();

        var newObject = {};
        for (var prop in object) {
          newObject[prop] = object[prop];
        }
        return newObject;
    }

    //// Metodi per impostare proprietà "nascoste" all'interno degli oggetti 
    //// (tipicamente usati per memorizzare l'AppComponentInfo di un dato componente dell'app
    ////  o i dati riguardanti l'initialize patchata nei componenti backbone)

    // NOTA DI SVILUPPO: non memorizzare le proprietà nascoste in oggetti contenitori 
    // in quanto sarebbero condivise da tutti i cloni / istanze e sottotipi
    // (quest'ultime in caso di proprietà nascoste impostate nel prototype del tipo), 
    // infatti gli oggetti sono copiati per riferimento.

    // @private
    // Prefisso dei nomi delle proprietà nascoste
    var hiddenPropertyPrefix = "__backboneDebugger__";
    // @private
    var getHiddenProperty = function(object, property) {
        if (typeof object !== "object") return;
        return object[hiddenPropertyPrefix+property];
    };
    // @private
    var setHiddenProperty = function(object, property, value) {
        if (typeof object !== "object") return;
        object[hiddenPropertyPrefix+property] = value;
    };

    ////

    // @private
    // instancePatcher è una funzione che viene chiamata ad ogni istanziazione del componente Backbone
    // specificato (e dei suoi sottotipi), passandogli la nuova istanza.
    // I componenti Backbone validi sono Backbone.View, Backbone.Model, Backbone.Collection e Backbone.Router
    // N.B: suppone che il componente backbone sia stato settato solo inizialmente.
    var patchBackboneComponent = bind(function(BackboneComponent, instancePatcher) {
    	onceSetted(BackboneComponent, "extend", function() {
            // (l'extend è l'ultimo metodo impostato, quindi ora il componente è pronto)

            // Patcha la initialize del componente (e dei suoi sottotipi) per intercettare
            // le istanze create, il meccanismo quindi funziona se i sottotipi non definiscono
            // costruttori custom che non chiamano la initialize.

            var patchInitialize = function(originalInitialize) {
                return function() {
                    // Patcha l'istanza se non è già stato fatto
                    // (se ad es. l'istanza chiama l'initialize definita nel padre, evita
                    // di patcharla due volte)
                    var isInstancePatched = getHiddenProperty(this, "isInstancePatched");
                    if (!isInstancePatched) {<commit_msg>Fix 'is object' check<commit_after>//console.log("Running backbone agent");

window.__backboneAgent = new (function() {

    //// METODI DI UTILITÀ ////

    // Imposta il this nella funzione func pari all'oggetto scope.
    var bind = function(func, scope) {
        return function() {
            return func.apply(scope, arguments);
        }
    }

    // @private
    // Nota: null non è considerato un oggetto.
    var isObject = function(target) {
        return typeof target == "object" && target !== null;
    }

    // @private
    var isArray = function(object) {
        return Object.prototype.toString.call(object) == '[object Array]';
    }

    // @private
    // Restituisce un clone dell'oggetto passato.
    // N.B: le sottoproprietà non saranno clonate (shallow clone).
    var clone = function(object) {
        if (!isObject(object)) return object;
        if (isArray(object)) return object.slice();

        var newObject = {};
        for (var prop in object) {
          newObject[prop] = object[prop];
        }
        return newObject;
    }

    // @private
    var watchOnce = function(object, property, callback) {
        watch(object, property, function onceHandler(prop, action, newvalue, oldvalue) {
            // facendo l'unwatch prima di chiamare la callback (invece di farlo dopo),
            // è possibile in quest'ultima impostare la proprietà property 
            // senza incorrere in un loop infinito.
            unwatch(object, property, onceHandler);

            callback(prop, action, newvalue, oldvalue);     
        });
    }

    // @private
    // Esegue la callback ogni volta che viene settata la proprietà property sull'oggetto object
    var onSetted = function(object, property, callback) {
        watch(object, property, function(prop, action, difference, oldvalue) {
            if (action == "set") { callback(); }
        }, 0);
    }

    // @private
    // Come la onSetted, ma la callback viene chiamata solo LA PRIMA VOLTA che la proprietà è settata.
    var onceSetted = function(object, property, callback) {
        watchOnce(object, property, function(prop, action, difference, oldvalue) {
            if (action == "set") { callback(); }
        }, 0);
    }

    // @private
    // Utilizza le librerie watch.js e Object.observe.poly.js per monitorare i set
    // della proprietà property di object e delle sue sottoproprietà, comprese quelle che
    // non sono presenti all'avvio del watching in quanto aggiunte successivamente.
    // Il livello di profondità del watching è specificato da recursionLevel (come in watch.js):
    // undefined => ricorsione completa, 0 => no ricorsione (solo il livello 0), n>0 => dal livello 0 al livello n)
    var onSettedDeep = function(object, property, onChange, recursionLevel) {

        // funzione per monitorare le sottoproprietà, esistenti e aggiunte successivamente
        var handleSubProperties = function(parentObject) {
            if (recursionLevel !== 0 && isObject(parentObject)) {
                var subRecursionLevel = (recursionLevel===undefined)? recursionLevel : recursionLevel-1;

                // monitora le sottoproprietà esistenti
                for (var subProperty in parentObject) {
                    if (parentObject.hasOwnProperty(subProperty)) {
                        onSettedDeep(parentObject, subProperty, onChange, subRecursionLevel);
                    }
                }

                // monitora le sottoproprietà aggiunte successivamente
                Object.observe(object[property], function(updates) {
                    for (var i=0,l=updates.length; i<l; i++) {
                        var update = updates[i];
                        var subProperty = update.name;

                        if (update.type == "new") { // nuova sottoproprietà
                            onSettedDeep(parentObject, subProperty, onChange, subRecursionLevel);

                            onChange();
                        }
                    } 
                });
            }
        }

        // monitora i set della property
        onSetted(object, property, function() {
            // monitora i set per le sottoproprietà del nuovo (eventuale) oggetto settato
            handleSubProperties(object[property]);
            
            onChange(); 
        });

        // monitora i set delle sottoproprietà
        handleSubProperties(object[property]);
    }

    // @private
    // Sostituisce la funzione functionName di object con quella restituita dalla funzione patcher.
    // La funzione patcher viene chiamata con la funzione originale come argomento.
    var patchFunction = function(object, functionName, patcher) {
        var originalFunction = object[functionName];
        object[functionName] = patcher(originalFunction);
    }

    // @private
    // Come patchFunction, ma aspetta che il metodo sia settato se questo è undefined al momento
    // della chiamata.
    var patchFunctionLater = function(object, functionName, patcher) {
        if (object[functionName] === undefined) {
            onceSetted(object, functionName, function() {
                patchFunction(object, functionName, patcher);
            });
        } else {
            patchFunction(object, functionName, patcher);
        }
    }

    ////

    // @private
    // Azione di un componente dell'app.
    var AppComponentAction = function(type, name, target, targetKind) {
        
        this.timestamp = Date.now();
        this.type = type; // stringa
        this.name = name; // stringa
        this.target = target; // oggetto
        this.targetKind = targetKind || "Other"; // può essere "AppComponent", "jQuery Event" o "Other"
        
        //// Metodi di utilità ////
         
        // stampa nella console le informazioni sull'azione
        this.printDetailsInConsole = function() {
        }
    }

    // @private
    var AppComponentInfo = function(category, index, component, actions) {

        // nome del componente Backbone di cui questo componente dell'app è un discendente.
        // I valori validi sono "View", "Model", "Collection", "Router"
        this.category = category;
        // usato come identificatore tra tutti i componenti dell'app della sua categoria
        this.index = index;

        this.component = component; // oggetto
        this.actions = actions || []; // array di oggetti AppComponentAction
    } 
        
    // @private
    // All'atto dell'istanziazione di un componente, l'agent gli assegna
    // un indice che lo identifica all'interno dei vari array
    // riguardanti i componenti di quella categoria.
    // Tale indice viene calcolato incrementando quello dell'ultimo componente
    // della propria categoria.
    var lastAppComponentsIndex = {
        "View": -1,
        "Model": -1,
        "Collection": -1,
        "Router": -1
    };

    //// API PUBBLICA ////
    
    // Informazioni sui componenti dell'applicazione.
    // Hash <"componentCategory", [AppComponentInfo]>.
    // (Gli indici degli array sono quelli dei componenti.)
    this.appComponentsInfo = {
        "View": [],
        "Model": [],
        "Collection": [],
        "Router": []
    };

    // Restituisce un array con gli indici dei componenti dell'applicazione
    // della categoria specificata che sono presenti nell'app.
    this.getAppComponentsIndexes = bind(function(appComponentCategory) {
        var appComponentsInfo = this.appComponentsInfo[appComponentCategory];

        var appComponentsIndexes = [];
        for (var appComponentIndex in appComponentsInfo) {
            if (appComponentsInfo.hasOwnProperty(appComponentIndex)) {
                appComponentsIndexes.push(appComponentIndex);
            }
        }
        return appComponentsIndexes;
    }, this);
    
    // Restituisce l'oggetto di tipo AppComponentInfo con le informazioni sul componente dell'app passato
    // o undefined se l'oggetto passato non è un componente valido.
    this.getAppComponentInfo = bind(function(appComponent) {
        return getHiddenProperty(appComponent, "appComponentInfo");
    }, this);

    this.getAppComponentInfoByIndex = bind(function(appComponentCategory, appComponentIndex) {
        var appComponentInfo = this.appComponentsInfo[appComponentCategory][appComponentIndex];
        return appComponentInfo;
    }, this);

    // Restituisce l'info della vista a cui appartiene l'elemento html passato, o undefined se non esiste.
    // L'elemento appartiene alla vista se questo combacia perfettamente con la sua proprietà el, o 
    // se questa è l'ascendente più vicino rispetto a tutte le altre viste.
    this.getAppViewInfoFromElement = bind(function(pageElement) {
        // funzione che controlla se l'elemento html target è un ascendente dell'elemento html of
        var isAscendant = function(target, of) {
            if (!of) return false;

            var ofParent = of.parentNode;
            if (target === ofParent) return true;
            return isAscendant(target, ofParent);
        }

        // cerca il miglior candidato
        var candidateViewInfo = undefined;
        var viewsIndexes = this.getAppComponentsIndexes("View");
        for (var i=0,l=viewsIndexes.length; i<l; i++) {
            var currentViewInfo = this.getAppComponentInfoByIndex("View", viewsIndexes[i]);
            var currentView = currentViewInfo.component;

            if (currentView.el === pageElement) {
                // candidato perfetto trovato
                candidateViewInfo = currentViewInfo;
                break;
            }
            // l'el di currentView è un ascendente di pageElement ed è un discendente del miglior
            // candidato trovato finora?
            var candidateView = candidateViewInfo? candidateViewInfo.component : undefined;
            var isBetterCandidate = isAscendant(currentView.el, pageElement) &&
                                   (!candidateView || isAscendant(candidateView.el, currentView.el));
            if (isBetterCandidate) {
                // candidato migliore trovato
                candidateViewInfo = currentViewInfo;
            }
        }
        return candidateViewInfo;
    }, this);

    //// Metodi per impostare proprietà "nascoste" all'interno degli oggetti 
    //// (tipicamente usati per memorizzare l'AppComponentInfo di un dato componente dell'app
    ////  o i dati riguardanti l'initialize patchata nei componenti backbone)

    // NOTA DI SVILUPPO: non memorizzare le proprietà nascoste in oggetti contenitori 
    // in quanto sarebbero condivise da tutti i cloni / istanze e sottotipi
    // (quest'ultime in caso di proprietà nascoste impostate nel prototype del tipo), 
    // infatti gli oggetti sono copiati per riferimento.

    // @private
    // Prefisso dei nomi delle proprietà nascoste
    var hiddenPropertyPrefix = "__backboneDebugger__";
    // @private
    var getHiddenProperty = function(object, property) {
        if (!isObject(object)) return;
        return object[hiddenPropertyPrefix+property];
    };
    // @private
    var setHiddenProperty = function(object, property, value) {
        if (!isObject(object)) return;
        object[hiddenPropertyPrefix+property] = value;
    };

    ////

    // @private
    // instancePatcher è una funzione che viene chiamata ad ogni istanziazione del componente Backbone
    // specificato (e dei suoi sottotipi), passandogli la nuova istanza.
    // I componenti Backbone validi sono Backbone.View, Backbone.Model, Backbone.Collection e Backbone.Router
    // N.B: suppone che il componente backbone sia stato settato solo inizialmente.
    var patchBackboneComponent = bind(function(BackboneComponent, instancePatcher) {
    	onceSetted(BackboneComponent, "extend", function() {
            // (l'extend è l'ultimo metodo impostato, quindi ora il componente è pronto)

            // Patcha la initialize del componente (e dei suoi sottotipi) per intercettare
            // le istanze create, il meccanismo quindi funziona se i sottotipi non definiscono
            // costruttori custom che non chiamano la initialize.

            var patchInitialize = function(originalInitialize) {
                return function() {
                    // Patcha l'istanza se non è già stato fatto
                    // (se ad es. l'istanza chiama l'initialize definita nel padre, evita
                    // di patcharla due volte)
                    var isInstancePatched = getHiddenProperty(this, "isInstancePatched");
                    if (!isInstancePatched) {
{'fraction_non_alphanumeric': 0.08958759988756375, 'fraction_numerical': 0.0011243625266032205, 'mean_word_length': 2.3156703501531086, 'pattern_counts': {'":': 16, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6592323', 'n_tokens_mistral': 6867, 'n_tokens_neox': 6702, 'n_words': 2050}