docs: function normalizeChildren(
  	ctx, container, subtypeName, containerObj, validationSets) {
  
  	// validate type if polymorphic object container
  	let subtype;
  	if (container.isPolymorphObject()) {
  		subtype = containerObj[container.typePropertyName];
  		if (((typeof subtype) !== 'string') || !container.hasProperty(subtype)) {
  			ctx.addErrorFor(
  				ctx.currentPointer.toString() + '/' + container.typePropertyName,
  				'{invalidType}');
  			return;
  		}
  	}
  
  	// go over container properties
  	for (let propName of container.allPropertyNames) {
  		const propDesc = container.getPropertyDesc(propName);
  
  		// skip views
  		if (propDesc.isView())
  			continue;
  
  		// check if subtype
  		if (propDesc.isSubtype()) {
  			if (propDesc.name === subtype) {
  				normalizeChildren(
  					ctx, propDesc.nestedProperties, subtype, containerObj,
  					validationSets);
  				const validators = getValidators(propDesc, false, validationSets);
  				if (validators)
  					for (let validator of validators)
  						validator(ctx, containerObj);
  			}
  			continue;
  		}
  
  		// get property value from the record
  		const originalValue = containerObj[propName];
  
  		// descend into validating the property
  		ctx.descend(
  			(subtypeName ? subtypeName + ':' + propName : propName),
  			containerObj
  		);
  
  		// validate property's nested elements if any
  		let value = originalValue;
  		if (propDesc.isArray()) {
  			if (Array.isArray(value) && (value.length > 0)) {
  				const elementValidators = getValidators(
  					propDesc, true, validationSets);
  				if (propDesc.scalarValueType === 'object') {
  					for (let i = 0, len = value.length; i < len; i++) {
  						const originalElementValue = value[i];
  						let elementValue = originalElementValue;
  						ctx.descend(String(i), value);
  						if (((typeof elementValue) === 'object') &&
  							(elementValue !== null))
  							normalizeChildren(
  								ctx, propDesc.nestedProperties, null,
  								elementValue, validationSets);
  						if (elementValidators) {
  							for (let validator of elementValidators)
  								elementValue = validator(ctx, elementValue);
  							if (elementValue !== originalElementValue)
  								value[i] = elementValue;
  						}
  						ctx.ascend();
  					}
  				} else if (elementValidators) {
  					for (let i = 0, len = value.length; i < len; i++) {
  						const originalElementValue = value[i];
  						let elementValue = originalElementValue;
  						ctx.descend(String(i), value);
  						for (let validator of elementValidators)
  							elementValue = validator(ctx, elementValue);
  						if (elementValue !== originalElementValue)
  							value[i] = elementValue;
  						ctx.ascend();
  					}
  				}
  			}
  		} else if (propDesc.isMap()) {
  			if (((typeof value) === 'object') && (value !== null)) {
  				const keys = Object.keys(value);
  				const elementValidators = getValidators(
  					propDesc, true, validationSets);
  				if (propDesc.scalarValueType === 'object') {
  					for (let key of keys) {
  						const originalElementValue = value[key];
  						let elementValue = originalElementValue;
  						ctx.descend(key, value);
  						if (((typeof elementValue) === 'object') &&
  							(elementValue !== null))
  							normalizeChildren(
  								ctx, propDesc.nestedProperties, null,
  								elementValue, validationSets);
  						if (elementValidators) {
  							for (let validator of elementValidators)
  								elementValue = validator(ctx, elementValue);
  							if (elementValue !== originalElementValue)
  								value[key] = elementValue;
  						}
  						ctx.ascend();
  					}
  				} else if (elementValidators) {
  					for (let key of keys) {
  						const originalElementValue = value[key];
  						let elementValue = originalElementValue;
  						ctx.descend(key, value);
  						for (let validator of elementValidators)
  							elementValue = validator(ctx, elementValue);
  						if (elementValue !== originalElementValue)
  							value[key] = elementValue;
  						ctx.ascend();
  					}
  				}
  			}
  		} else if ((propDesc.scalarValueType === 'object') &&
  			((typeof value) === 'object') && (value !== null)) {
  			normalizeChildren(
  				ctx, propDesc.nestedProperties, null, value, validationSets);
  		}
  
  		// run property validators
  		const validators = getValidators(propDesc, false, validationSets);
  		if (validators)
  			for (let validator of validators)
  				value = validator(ctx, value);
  
  		// replace original value in the record if was normalized
  		if (value !== originalValue)
  			containerObj[propName] = value;
  
  		// ascend from the property validation
  		ctx.ascend();
  	}
  }