<commit_before>/**
 * Backbone-Nested 1.1.0 - 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)
 */
/*global Backbone, _, $ */
(function(){
  'use strict';

  Backbone.NestedModel = Backbone.Model.extend({

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

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

      // 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(key, value, opts){
      // if it's an attribute path, convert back to string
      if (_.isArray(key)) {
        key = Backbone.NestedModel.createAttrStr(key);
      }

      var attrs;
      // check that it's an object, or null/undefined
      if (_.isObject(key) || key == null) {
        attrs = key;
        opts = value;
      } else {
        // Backbone 0.9.0+ syntax - `model.set(key, val)`
        attrs = {};
        attrs[key] = value;
      }
      opts = opts || {};

      var newAttrs = Backbone.NestedModel.deepClone(this.attributes),
        attrVal, attrPath, attrObj;
      
      for (var attrStr in attrs){
        attrPath = Backbone.NestedModel.attrPath(attrStr);
        attrObj = Backbone.NestedModel.createAttrObj(attrPath, attrs[attrStr]);

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

      return Backbone.NestedModel.__super__.set.call(this, newAttrs, opts);
    },

    unset: function(attrStr, opts){
      opts = _.extend({}, opts, {unset: true});
      this.set(attrStr, null, opts);

      return this;
    },

    add: function(attrStr, value, opts){
      var current = this.get(attrStr, {silent: true});
      this.set(attrStr + '[' + current.length + ']', value, opts);
    },

    remove: function(attrStr, opts){
      opts = opts || {};

      var attrPath = Backbone.NestedModel.attrPath(attrStr),
        aryPath = _.initial(attrPath),
        val = this.get(aryPath, {silent: true}),
        i = _.last(attrPath);

      if (!_.isArray(val)){
        throw new Error("remove() must be called on a nested array");
      }

      // only trigger if an element is actually being removed
      var trigger = !opts.silent && (val.length > i + 1),
        oldEl = val[i];

      // remove the element from the array
      val.splice(i, 1);
      this.set(aryPath, val, opts);

      if (trigger){
        this.trigger('remove:' + Backbone.NestedModel.createAttrStr(aryPath), this, oldEl);
      }

      return this;
    },

    toJSON: function(){
      return Backbone.NestedModel.deepClone(this.attributes);
    },


    // 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] = [];
        }

        if (prop in dest && _.isObject(sourceVal) && _.isObject(destVal)){
          destVal = dest[prop] = this._mergeAttrs(destVal, sourceVal, opts, newStack);
        } else {
          var oldVal = destVal;

          destVal = dest[prop] = sourceVal;

          if (_.isArray(dest) && !opts.silent){<commit_msg>refactored set() to be more efficient<commit_after>/**
 * Backbone-Nested 1.1.0 - 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)
 */
/*global Backbone, _, $ */
(function(){
  'use strict';

  Backbone.NestedModel = Backbone.Model.extend({

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

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

      // 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(key, value, opts){
      var newAttrs = Backbone.NestedModel.deepClone(this.attributes);

      if (_.isString(key)) {
        // Backbone 0.9.0+ syntax: `model.set(key, val)` - convert the key to an attribute path
        key = Backbone.NestedModel.attrPath(key);
      }

      if (_.isArray(key)) {
        // attribute path
        this._mergeAttr(newAttrs, key, value, opts);
      } else { // it's an Object
        opts = value;
        var attrs = key,
          attrPath;

        for (var attrStr in attrs){
          attrPath = Backbone.NestedModel.attrPath(attrStr);
          this._mergeAttr(newAttrs, attrPath, attrs[attrStr], opts);
        }
      }

      return Backbone.NestedModel.__super__.set.call(this, newAttrs, opts);
    },

    unset: function(attrStr, opts){
      opts = _.extend({}, opts, {unset: true});
      this.set(attrStr, null, opts);

      return this;
    },

    add: function(attrStr, value, opts){
      var current = this.get(attrStr, {silent: true});
      this.set(attrStr + '[' + current.length + ']', value, opts);
    },

    remove: function(attrStr, opts){
      opts = opts || {};

      var attrPath = Backbone.NestedModel.attrPath(attrStr),
        aryPath = _.initial(attrPath),
        val = this.get(aryPath, {silent: true}),
        i = _.last(attrPath);

      if (!_.isArray(val)){
        throw new Error("remove() must be called on a nested array");
      }

      // only trigger if an element is actually being removed
      var trigger = !opts.silent && (val.length > i + 1),
        oldEl = val[i];

      // remove the element from the array
      val.splice(i, 1);
      this.set(aryPath, val, opts);

      if (trigger){
        this.trigger('remove:' + Backbone.NestedModel.createAttrStr(aryPath), this, oldEl);
      }

      return this;
    },

    toJSON: function(){
      return Backbone.NestedModel.deepClone(this.attributes);
    },


    // private

    // note: modifies `newAttrs`
    _mergeAttr: function(newAttrs, attrPath, value, opts){
      var attrObj = Backbone.NestedModel.createAttrObj(attrPath, value);
      this._mergeAttrs(newAttrs, attrObj, opts);
    },

    // note: modifies `dest`
    _mergeAttrs: function(dest, source, opts, stack){
      opts = opts || {};
      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] = [];
        }

        if (prop in dest && _.isObject(sourceVal) && _.isObject(destVal)){
          destVal = dest[prop] = this._mergeAttrs(destVal, sourceVal, opts, newStack);
        } else {
          var oldVal = destVal;

          destVal = dest[prop] = sourceVal;

          if (_.isArray(dest) && !opts.silent){
{'fraction_non_alphanumeric': 0.13938028169014086, 'fraction_numerical': 0.004507042253521127, 'mean_word_length': 2.2740686093692366, 'pattern_counts': {'":': 0, '<': 7, '<?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': '5066381', 'n_tokens_mistral': 2755, 'n_tokens_neox': 2680, 'n_words': 692}