define([
  '../core',
  '../var/rnotwhite',
  './accepts'
], function (jQuery, rnotwhite) {
  function Data () {
    // Support: Android<4,
    // Old WebKit does not have Object.preventExtensions/freeze method,
    // return new empty object instead with no [[set]] accessor
    Object.defineProperty(this.cache = {}, 0, {
      get: function () {
        return {}
      }
    })

    this.expando = jQuery.expando + Data.uid++
  }

  Data.uid = 1
  Data.accepts = jQuery.acceptData

  Data.prototype = {
    key: function (owner) {
      // We can accept data for non-element nodes in modern browsers,
      // but we should not, see #8335.
      // Always return the key for a frozen object.
      if (!Data.accepts(owner)) {
        return 0
      }

      var descriptor = {}
      // Check if the owner object already has a cache key
      var unlock = owner[this.expando]

      // If not, create one
      if (!unlock) {
        unlock = Data.uid++

        // Secure it in a non-enumerable, non-writable property
        try {
          descriptor[this.expando] = { value: unlock }
          Object.defineProperties(owner, descriptor)

          // Support: Android<4
          // Fallback to a less secure definition
        } catch (e) {
          descriptor[this.expando] = unlock
          jQuery.extend(owner, descriptor)
        }
      }

      // Ensure the cache object
      if (!this.cache[unlock]) {
        this.cache[unlock] = {}
      }

      return unlock
    },
    set: function (owner, data, value) {
      var prop
      // There may be an unlock assigned to this node,
      // if there is no entry for this "owner", create one inline
      // and set the unlock as though an owner entry had always existed
      var unlock = this.key(owner)
      var cache = this.cache[unlock]

      // Handle: [ owner, key, value ] args
      if (typeof data === 'string') {
        cache[data] = value

        // Handle: [ owner, { properties } ] args
      } else {
        // Fresh assignments by object are shallow copied
        if (jQuery.isEmptyObject(cache)) {
          jQuery.extend(this.cache[unlock], data)
          // Otherwise, copy the properties one-by-one to the cache object
        } else 

      }
      return cache
    },
    get: function (owner, key) {
      // Either a valid cache is found, or will be created.
      // New caches will be created and the unlock returned,
      // allowing direct access to the newly created
      // empty data object. A valid owner object must be provided.
      var cache = this.cache[this.key(owner)]

      return key === undefined
        ? cache : cache[key]
    },
    access: function (owner, key, value) {
      var stored
      // In cases where either:
      //
      //   1. No key was specified
      //   2. A string key was specified, but no value provided
      //
      // Take the "read" path and allow the get method to determine
      // which value to return, respectively either:
      //
      //   1. The entire cache object
      //   2. The data stored at the key
      //
      if (key === undefined ||
				((key && typeof key === 'string') && value === undefined)) {
        stored = this.get(owner, key)

        return stored !== undefined
          ? stored : this.get(owner, jQuery.camelCase(key))
      }

      // [*]When the key is not a string, or both a key and value
      // are specified, set or extend (existing objects) with either:
      //
      //   1. An object of properties
      //   2. A key and value
      //
      this.set(owner, key, value)

      // Since the "set" path can have two possible entry points
      // return the expected data based on which path was taken[*]
      return value !== undefined ? value : key
    },
    remove: function (owner, key) {
      var i; var name; var camel
      var unlock = this.key(owner)
      var cache = this.cache[unlock]

      if (key === undefined) {
        this.cache[unlock] = {}
      } else {
        // Support array or space separated string of keys
        if (jQuery.isArray(key)) {
          // If "name" is an array of keys...
          // When data is initially created, via ("key", "val") signature,
          // keys will be converted to camelCase.
          // Since there is no way to tell _how_ a key was added, remove
          // both plain key and camelCase key. #12786
          // This will only penalize the array argument path.
          name = key.concat(key.map(jQuery.camelCase))
        } else {
          camel = jQuery.camelCase(key)
          // Try the string as a key before any manipulation
          if (key in cache) {
            name = [key, camel]
          } else {
            // If a key with the spaces exists, use it.
            // Otherwise, create an array by matching non-whitespace
            name = camel
            name = name in cache
              ? [name] : (name.match(rnotwhite) || [])
          }
        }

        i = name.length
        while (i--) {
          delete cache[name[i]]
        }
      }
    },
    hasData: function (owner) {
      return !jQuery.isEmptyObject(
        this.cache[owner[this.expando]] || {}
      )
    },
    discard: function (owner) {
      if (owner[this.expando]) {
        delete this.cache[owner[this.expando]]
      }
    }
  }

  return Data
})

{
          for (prop in data) {
            cache[prop] = data[prop]
          }
        }