static private bool DenormalizeMessenger <E>(ICard2 card, ITypedProperty <E> prop, int index) where E : ExtendibleEnum
        {
            string typeVal = prop.RawProperty.TextValue.Split(':').FirstOrDefault() ?? "Messenger";

            if (typeVal.Length > 1)
            {
                typeVal = typeVal.First().ToString().ToUpper() + typeVal.Substring(1); // Make first letter capital.
            }
            // Add "itemX.PROP" property.
            string applePropName = string.Format("item10{0}.IMPP", index);

            prop.RawProperty.Parameters.Add(new Parameter("X-SERVICE-TYPE", typeVal));

            card.AddProperty(applePropName, prop.RawProperty);

            // Add itemN.X-ABLabel property.

            string        appleLabelPropName = string.Format("item10{0}.X-ABLabel", index);
            ITextProperty appleLabelProp     = card.CreateTextProp(typeVal);

            appleLabelProp.RawProperty.SortIndex = prop.RawProperty.SortIndex;
            card.AddProperty(appleLabelPropName, appleLabelProp.RawProperty);

            return(true);
        }
        static private bool NormalizeProps(ICard2 card)
        {
            bool modified = false;

            // Find props with "itemX." prefix. Copy props to new list.
            var appleProps = card.Properties.Where(x => x.Key.Contains(".")).ToList();

            List <string> propNamesToDelete = new List <string>();

            foreach (KeyValuePair <string, IList <IRawProperty> > keyValProps in appleProps)
            {
                // Typically iOS / OS X provides 2 props instead of one for each vCard property, for example:
                // item2.TEL:(222)222 - 2222
                // item2.X-ABLabel:Emergency

                // Get regular vCard prop name ("TEL") from Apple prop name ("item2.TEL").
                int dotIndex = keyValProps.Key.IndexOf('.');
                if ((dotIndex < 0) || (dotIndex == keyValProps.Key.Length - 1))
                {
                    continue;
                }

                string fixedName = keyValProps.Key.Substring(dotIndex + 1);

                if (fixedName.StartsWith("X-"))
                {
                    continue;
                }

                IRawProperty prop = keyValProps.Value.First(); // There is always only one property itemN.PROP in the list in case of iOS / OS X.

                // Find itemN.X-ABLabel property.
                string labelPropName = keyValProps.Key.Substring(0, dotIndex) + ".X-ABLabel";
                if (card.Properties.ContainsKey(labelPropName))
                {
                    IRawProperty propLabel = card.Properties[labelPropName].FirstOrDefault();

                    // Remove _$!< and >!$_ around value.
                    string typeVal = propLabel.TextValue.Replace("_$!<", "").Replace(">!$_", "");

                    // Add itemN.X-ABLabel property value to the list of TYPE parameter values.
                    prop.Parameters.Add(new Parameter("TYPE", typeVal));

                    propNamesToDelete.Add(labelPropName);
                }

                // Add "PROP" propery instead of "itemN.PROP".
                card.AddProperty(fixedName, prop);

                propNamesToDelete.Add(keyValProps.Key);

                modified = true;
            }

            // Remove "itemX.PROP" props.
            propNamesToDelete.ForEach(propName => card.Properties.Remove(propName));

            return(modified);
        }
        static private bool DenormalizeTypedProperty <E>(ICard2 card, ITypedProperty <E> prop, string propName, int index,
                                                         IEnumerable <string> supportedStandardTypes, IEnumerable <string> customLabelMetaTypes) where E : ExtendibleEnum
        {
            // Find first non-standard type param and move it to item2.X-ABLabel property.
            foreach (E type in prop.Types)
            {
                string typeVal = type.Name;
                if (supportedStandardTypes.Contains(typeVal.ToUpper()))
                {
                    continue; // No need to change, continue searching.
                }

                if (customLabelMetaTypes.Contains(typeVal.ToUpper()))
                {
                    // Must be converted to itemN.X-ABLabel:_$!<Other>!$_
                    typeVal = string.Format("_$!<{0}>!$_", typeVal);
                }

                // Remove this param value from TYPE.
                prop.Types = prop.Types.Where(x => x != type).ToArray();

                // Add "itemX.PROP" property.
                string applePropName = string.Format("item10{0}.{1}", index, propName);
                card.AddProperty(applePropName, prop.RawProperty);

                // Add itemN.X-ABLabel property.
                string        appleLabelPropName = string.Format("item10{0}.X-ABLabel", index);
                ITextProperty appleLabelProp     = card.CreateTextProp(typeVal);
                appleLabelProp.RawProperty.SortIndex = prop.RawProperty.SortIndex;
                card.AddProperty(appleLabelPropName, appleLabelProp.RawProperty);

                return(true);
            }

            return(false);
        }