public static VCardFile ReadFrom(TextReader reader)
        {
            VCardFile file = new VCardFile();

            string line;

            while (reader.Peek() != -1)
            {
                VCardEntry entry = new VCardEntry("");
                line = reader.ReadLine();
                line = reader.ReadLine();
                while (line.ToLower() != "end:vcard")
                {
                    ContentLine res = ParseLine(string.Empty, line);
                    entry.Contents.Add(res);
                    line = reader.ReadLine();
                }
                file.Entries.Add(entry);
            }
            return(file);
        }
        public static ContentLine ParseLine(string gname, string line)
        {
            var match = _contentLineRegex.Match(line);

            // Match m = Regex.Match(line, @"^(?<groupname>[.*\.])(?<tag>[A-Za-z]*)[:;]");//[.]*\.      [././]*
            if (match.Success)
            {
                var allTokens = Enum.GetValues(typeof(ContentLinePartName)).OfType <ContentLinePartName>().SelectMany(
                    pn => match.Groups[pn.ToString()].Captures.OfType <Capture>()
                    .Select(c => new { pn, c.Value, c.Index })
                    ).OrderBy(p => p.Index).Select(c => new KeyValuePair <ContentLinePartName, string>(c.pn, c.Value.Trim())).ToArray();

                var tokens = new Queue <KeyValuePair <ContentLinePartName, string> >(allTokens);
                var token  = tokens.Dequeue();
                if (token.Key == ContentLinePartName.group)
                {
                    if (token.Value == gname)
                    {
                        throw new NotImplementedException("Invalid group");
                    }

                    token = tokens.Dequeue();
                }

                if (token.Key != ContentLinePartName.name)
                {
                    throw new NotImplementedException("Invalid name");
                }

                var lineName = token.Value;
                token = tokens.Dequeue();

                var lineParams = new List <Param>();
                while (token.Key == ContentLinePartName.param)
                {
                    var paramName   = token.Value;
                    var paramValues = new List <string>();
                    token = tokens.Dequeue();
                    while (token.Key == ContentLinePartName.pvalue)
                    {
                        paramValues.Add(token.Value);
                        token = tokens.Dequeue();
                    }

                    lineParams.Add(new Param(paramName, paramValues.ToArray()));
                }
                if (token.Key != ContentLinePartName.value)
                {
                    throw new NotImplementedException("Invalid value");
                }
                var lineValue = token.Value;

                ContentLine contentLine = new ContentLine(
                    lineName,
                    lineValue,
                    lineParams.ToArray()
                    );
                return(contentLine);
            }
            return(null);
        }