<commit_before>/**
 * Backbone-Nested 1.0.1 - An extension of Backbone.js that keeps track of nested attributes
 *
 * http://afeld.github.com/backbone-nested/
 *
 * Copyright (c) 2011-2012 <NAME>
 * MIT Licensed (LICENSE)
 */
Backbone.NestedModel = Backbone.Model.extend({
  
  constructor: function(attrs, opts){
    Backbone.Model.prototype.constructor.apply( this, arguments );
  },

  get: function(attrStrOrPath, opts){
    opts || (opts = {});

    var attrPath = Backbone.NestedModel.attrPath(attrStrOrPath),
      childAttr = attrPath[0],
      result = Backbone.Model.prototype.get.call(this, childAttr);
    
    // walk through the child attributes
    for (var i = 1; i < attrPath.length; i++){
      childAttr = attrPath[i];
      result = result[childAttr];
      if (!result){
        // value not present
        break;
      }
    }

    // check if the result is an Object, Array, etc.
    if (!opts.silent && _.isObject(result) && window.console){
      window.console.log("Backbone-Nested syntax is preferred for accesing values of attribute '" + attrStrOrPath + "'.");
    }
    // else it's a leaf

    return result;
  },

  has: function(attr){
    // for some reason this is not how Backbone.Model is implemented - it accesses the attributes object directly
    var result = this.get(attr, {silent: true});
    return !(result === null || _.isUndefined(result));
  },

  set: function(attrs, opts){
    opts || (opts = {});
    var newAttrs = _.deepClone(this.attributes);

    for (var attrStr in attrs){
      var attrPath = Backbone.NestedModel.attrPath(attrStr),
        attrObj = Backbone.NestedModel.createAttrObj(attrPath, attrs[attrStr]);

      this.mergeAttrs(newAttrs, attrObj, opts);
    }

    return Backbone.Model.prototype.set.call(this, newAttrs, opts);
  },

  unset: function(attrStr, opts){
    var setOpts = {};
    setOpts[attrStr] = void 0;
    this.set(setOpts, opts);

    return this;
  },

  remove: function(attrStr, opts){
    this.unset(attrStr, opts);

    var attrPath = Backbone.NestedModel.attrPath(attrStr);
    if (_.isNumber(_.last(attrPath))){
      var aryPath = _.initial(attrPath),
        childAry = this.get(aryPath, {silent: true});
      
      // compact the array (remove falsy values)
      for (var i = 0; i < childAry.length; i++){
        if (!childAry[i]){
          childAry.splice(i, 1);
        }
      }
    }

    return this;
  },

  toJSON: function(){
    var json = Backbone.Model.prototype.toJSON();
    return _.deepClone(json);
  },


  // private

  mergeAttrs: function(dest, source, opts, stack){
    stack || (stack = []);

    _.each(source, function(sourceVal, prop){
      if (prop === '-1'){
        prop = dest.length;
      }

      var destVal = dest[prop],
        newStack = stack.concat([prop]),
        attrStr;

      var isChildAry = _.isObject(sourceVal) && _.any(sourceVal, function(val, attr){
        return attr === '-1' || _.isNumber(attr);
      });

      if (isChildAry && !_.isArray(destVal)){
        destVal = dest[prop] = [];
      }<commit_msg>fix NestedModel.toJSON()<commit_after>/**
 * Backbone-Nested 1.0.1 - An extension of Backbone.js that keeps track of nested attributes
 *
 * http://afeld.github.com/backbone-nested/
 *
 * Copyright (c) 2011-2012 <NAME>
 * MIT Licensed (LICENSE)
 */
Backbone.NestedModel = Backbone.Model.extend({
  
  constructor: function(attrs, opts){
    Backbone.Model.prototype.constructor.apply( this, arguments );
  },

  get: function(attrStrOrPath, opts){
    opts || (opts = {});

    var attrPath = Backbone.NestedModel.attrPath(attrStrOrPath),
      childAttr = attrPath[0],
      result = Backbone.Model.prototype.get.call(this, childAttr);
    
    // walk through the child attributes
    for (var i = 1; i < attrPath.length; i++){
      childAttr = attrPath[i];
      result = result[childAttr];
      if (!result){
        // value not present
        break;
      }
    }

    // check if the result is an Object, Array, etc.
    if (!opts.silent && _.isObject(result) && window.console){
      window.console.log("Backbone-Nested syntax is preferred for accesing values of attribute '" + attrStrOrPath + "'.");
    }
    // else it's a leaf

    return result;
  },

  has: function(attr){
    // for some reason this is not how Backbone.Model is implemented - it accesses the attributes object directly
    var result = this.get(attr, {silent: true});
    return !(result === null || _.isUndefined(result));
  },

  set: function(attrs, opts){
    opts || (opts = {});
    var newAttrs = _.deepClone(this.attributes);

    for (var attrStr in attrs){
      var attrPath = Backbone.NestedModel.attrPath(attrStr),
        attrObj = Backbone.NestedModel.createAttrObj(attrPath, attrs[attrStr]);

      this.mergeAttrs(newAttrs, attrObj, opts);
    }

    return Backbone.Model.prototype.set.call(this, newAttrs, opts);
  },

  unset: function(attrStr, opts){
    var setOpts = {};
    setOpts[attrStr] = void 0;
    this.set(setOpts, opts);

    return this;
  },

  remove: function(attrStr, opts){
    this.unset(attrStr, opts);

    var attrPath = Backbone.NestedModel.attrPath(attrStr);
    if (_.isNumber(_.last(attrPath))){
      var aryPath = _.initial(attrPath),
        childAry = this.get(aryPath, {silent: true});
      
      // compact the array (remove falsy values)
      for (var i = 0; i < childAry.length; i++){
        if (!childAry[i]){
          childAry.splice(i, 1);
        }
      }
    }

    return this;
  },

  toJSON: function(){
    var json = Backbone.Model.prototype.toJSON.apply(this);
    return _.deepClone(json);
  },


  // private

  mergeAttrs: function(dest, source, opts, stack){
    stack || (stack = []);

    _.each(source, function(sourceVal, prop){
      if (prop === '-1'){
        prop = dest.length;
      }

      var destVal = dest[prop],
        newStack = stack.concat([prop]),
        attrStr;

      var isChildAry = _.isObject(sourceVal) && _.any(sourceVal, function(val, attr){
        return attr === '-1' || _.isNumber(attr);
      });

      if (isChildAry && !_.isArray(destVal)){
        destVal = dest[prop] = [];
      }
{'fraction_non_alphanumeric': 0.1450642380874939, 'fraction_numerical': 0.005854610505773296, 'mean_word_length': 2.6870503597122304, 'pattern_counts': {'":': 0, '<': 9, '<?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': '7175935', 'n_tokens_mistral': 2006, 'n_tokens_neox': 1954, 'n_words': 477}