docs: function defineProperty(element, propertyName, descriptor, scope) {
    assert(element, 'Parameter \'element\' must be defined');
    assertType(descriptor, 'object', false, 'Parameter \'descriptor\' must be an object literal');
    assertType(descriptor.configurable, 'boolean', true, 'Optional configurable key in descriptor must be a boolean');
    assertType(descriptor.enumerable, 'boolean', true, 'Optional enumerable key in descriptor must be a boolean');
    assertType(descriptor.writable, 'boolean', true, 'Optional writable key in descriptor must be a boolean');
    assertType(descriptor.unique, 'boolean', true, 'Optional unique key in descriptor must be a boolean');
    assertType(descriptor.dirtyType, 'number', true, 'Optional dirty type must be of DirtyType enum (number)');
    assertType(descriptor.eventType, 'string', true, 'Optional event type must be a string');
    assertType(descriptor.attributed, 'boolean', true, 'Optional attributed must be a boolean');
    assertType(descriptor.onChange, 'function', true, 'Optional change handler must be a function');
    assertType(scope, 'string', true, 'Optional parameter \'scope\' must be a string');
  
    let dirtyType = descriptor.dirtyType;
    let defaultValue = descriptor.defaultValue;
    let attributed = descriptor.attributed;
    let attributeName = Directive.DATA+propertyName.replace(/([A-Z])/g, ($1) => ('-'+$1.toLowerCase()));
    let eventType = descriptor.eventType;
    let unique = descriptor.unique;
  
    assert(!attributeName || !hasOwnValue(Directive, attributeName), 'Attribute \'' + attributeName + '\' is reserved');
  
    if (unique === undefined) unique = true;
  
    if (scope === undefined) {
      scope = element;
    }
    else {
      assert(element.hasOwnProperty(scope), 'The specified Element instance does not have a property called \'' + scope + '\'');
      scope = element[scope];
    }
  
    if (defaultValue !== undefined) {
      scope.__private__ = scope.__private__ || {};
      Object.defineProperty(scope.__private__, propertyName, { value: defaultValue, writable: true });
    }
  
    let newDescriptor = {};
  
    if (descriptor.configurable !== undefined) newDescriptor.configurable = descriptor.configurable;
    if (descriptor.enumerable !== undefined) newDescriptor.enumerable = descriptor.enumerable;
    if (descriptor.value !== undefined) newDescriptor.value = descriptor.value;
    if (descriptor.writable !== undefined) newDescriptor.writable = descriptor.writable;
  
    if (descriptor.get) {
      newDescriptor.get = () => ((typeof descriptor.get === 'function') ? descriptor.get(scope.__private__[propertyName]) : scope.__private__[propertyName]);
    }
  
    if (descriptor.set) {
      newDescriptor.set = (val) => {
        let oldVal = scope.__private__[propertyName];
  
        if (typeof descriptor.set === 'function') val = descriptor.set(val);
  
        if (unique && (oldVal === val)) return;
  
        if (oldVal === undefined) {
          scope.__private__ = scope.__private__ || {};
          Object.defineProperty(scope.__private__, propertyName, { value: val, writable: true });
        }
        else {
          scope.__private__[propertyName] = val;
        }
  
        if (descriptor.onChange !== undefined) descriptor.onChange(oldVal, val);
        if (attributed === true) dom.setAttribute(element, attributeName, val);
        if ((dirtyType !== undefined) && (element.setDirty)) element.setDirty(dirtyType);
  
        if (eventType !== undefined) {
          let event = new CustomEvent(eventType, {
            detail: {
              property: propertyName,
              oldValue: oldVal,
              newValue: val
            }
          });
  
          if (element.dispatchEvent)
            element.dispatchEvent(event);
        }
      };
    }
  
    Object.defineProperty(scope, propertyName, newDescriptor);
  
    if (defaultValue !== undefined && attributed === true) {
      dom.setAttribute(element, attributeName, defaultValue);
    }
  
    if (defaultValue !== undefined && dirtyType !== undefined && element.nodeState >= NodeState.UPDATED && element.setDirty) {
      element.setDirty(dirtyType);
    }
  }