docs: function splitSchemaElements( modelName, schema = {}, errors = [] ) {
  	if ( !modelName || typeof modelName !== "string" ) {
  		throw new TypeError( "invalid name of model" );
  	}
  
  	if ( !schema || typeof schema !== "object" || Array.isArray( schema ) ) {
  		throw new TypeError( "invalid model schema definition" );
  	}
  
  
  	const keys = Object.keys( schema );
  
  	const attributes = {};
  	const computeds = {};
  	const hooks = {};
  
  	for ( let ki = 0, kLength = keys.length; ki < kLength; ki++ ) {
  		const key = keys[ki];
  
  		switch ( typeof schema[key] ) {
  			case "function" :
  				// got code computing derived attribute
  				computeds[key] = schema[key];
  				break;
  
  			case "object" : {
  				const value = schema[key];
  				if ( value ) {
  					if ( Array.isArray( value ) ) {
  						// check for list of event handlers
  						let allFunctions = true;
  
  						for ( let vi = 0, vLength = value.length; vi < vLength; vi++ ) {
  							if ( typeof value[vi] !== "function" ) {
  								allFunctions = false;
  								break;
  							}
  						}
  
  						if ( allFunctions ) {
  							hooks[key] = value.slice();
  							break;
  						}
  					} else {
  						// got regular attribute definition
  						if ( !ptnKeyword.test( key ) ) {
  							errors.push( new TypeError( `WARNING: ignoring attribute with invalid name ${key}` ) );
  						} else {
  							attributes[key] = schema[key];
  						}
  						break;
  					}
  				}
  			}
  
  			// falls through
  			default :
  				errors.push( new TypeError( `WARNING: invalid element ${key} in schema of model ${modelName}` ) );
  		}
  	}
  
  	return { attributes, computeds, hooks };
  }