text: /*!
   * Module dependencies.
   */
  
  'use strict';
  
  const EventEmitter = require('events').EventEmitter;
  const Subdocument = require('./subdocument');
  const utils = require('../utils');
  
  const documentArrayParent = require('../helpers/symbols').documentArrayParent;
  
  /*!
   * A constructor.
   *
   * @param {Object} obj js object returned from the db
   * @param {MongooseDocumentArray} parentArr the parent array of this document
   * @param {Boolean} skipId
   * @inherits Document
   * @api private
   */
  
  function ArraySubdocument(obj, parentArr, skipId, fields, index) {
    if (utils.isMongooseDocumentArray(parentArr)) {
      this.__parentArray = parentArr;
      this[documentArrayParent] = parentArr.$parent();
    } else {
      this.__parentArray = undefined;
      this[documentArrayParent] = undefined;
    }
    this.$setIndex(index);
    this.$__parent = this[documentArrayParent];
  
    Subdocument.call(this, obj, fields, this[documentArrayParent], skipId, { isNew: true });
  }
  
  /*!
   * Inherit from Subdocument
   */
  ArraySubdocument.prototype = Object.create(Subdocument.prototype);
  ArraySubdocument.prototype.constructor = ArraySubdocument;
  
  Object.defineProperty(ArraySubdocument.prototype, '$isSingleNested', {
    configurable: false,
    writable: false,
    value: false
  });
  
  Object.defineProperty(ArraySubdocument.prototype, '$isDocumentArrayElement', {
    configurable: false,
    writable: false,
    value: true
  });
  
  for (const i in EventEmitter.prototype) {
    ArraySubdocument[i] = EventEmitter.prototype[i];
  }
  
  /*!
   * ignore
   */
  
  ArraySubdocument.prototype.$setIndex = function(index) {
    this.__index = index;
  
    if (this.$__ != null && this.$__.validationError != null) {
      const keys = Object.keys(this.$__.validationError.errors);
      for (const key of keys) {
        this.invalidate(key, this.$__.validationError.errors[key]);
      }
    }
  };
  
  /*!
   * ignore
   */
  
  ArraySubdocument.prototype.populate = function() {
    throw new Error('Mongoose does not support calling populate() on nested ' +
      'docs. Instead of `doc.arr[0].populate("path")`, use ' +
      '`doc.populate("arr.0.path")`');
  };
  
  /*!
   * ignore
   */
  
  ArraySubdocument.prototype.$__removeFromParent = function() {
    const _id = this._doc._id;
    if (!_id) {
      throw new Error('For your own good, Mongoose does not know ' +
        'how to remove an ArraySubdocument that has no _id');
    }
    this.__parentArray.pull({ _id: _id });
  };
  
  /**
   * Returns the full path to this document. If optional `path` is passed, it is appended to the full path.
   *
   * @param {String} [path]
   * @param {Boolean} [skipIndex] Skip adding the array index. For example `arr.foo` instead of `arr.0.foo`.
   * @return {String}
   * @api private
   * @method $__fullPath
   * @memberOf ArraySubdocument
   * @instance
   */
  
  ArraySubdocument.prototype.$__fullPath = function(path, skipIndex) {
    if (this.__index == null) {
      return null;
    }
    if (!this.$__.fullPath) {
      this.ownerDocument();
    }
  
    if (skipIndex) {
      return path ?
        this.$__.fullPath + '.' + path :
        this.$__.fullPath;
    }
  
    return path ?
      this.$__.fullPath + '.' + this.__index + '.' + path :
      this.$__.fullPath + '.' + this.__index;
  };
  
  /*!
   * Given a path relative to this document, return the path relative
   * to the top-level document.
   */
  
  ArraySubdocument.prototype.$__pathRelativeToParent = function(path, skipIndex) {
    if (this.__index == null) {
      return null;
    }
    if (skipIndex) {
      return path == null ? this.__parentArray.$path() : this.__parentArray.$path() + '.' + path;
    }
    if (path == null) {
      return this.__parentArray.$path() + '.' + this.__index;
    }
    return this.__parentArray.$path() + '.' + this.__index + '.' + path;
  };
  
  /*!
   * Returns this sub-documents parent document.
   */
  
  ArraySubdocument.prototype.$parent = function() {
    return this[documentArrayParent];
  };
  
  /**
   * Returns this subdocument's parent array.
   *
   * ####Example:
   *
   *     const Test = mongoose.model('Test', new Schema({
   *       docArr: [{ name: String }]
   *     }));
   *     const doc = new Test({ docArr: [{ name: 'test subdoc' }] });
   *
   *     doc.docArr[0].parentArray() === doc.docArr; // true
   *
   * @api public
   * @method parentArray
   * @returns DocumentArray
   */
  
  ArraySubdocument.prototype.parentArray = function() {
    return this.__parentArray;
  };
  
  /*!
   * Module exports.
   */
  
  module.exports = ArraySubdocument;
  