public override async Task <IEnumerable <Entity> > RecognizeEntitiesAsync(DialogContext dialogContext, string text, string locale, IEnumerable <Entity> entities, CancellationToken cancellationToken = default)
        {
            List <Entity> newEntities = new List <Entity>();

            // Get data from incoming entities
            if (entities != null)
            {
                List <Entity> givenNames   = new List <Entity>();
                List <Entity> surnames     = new List <Entity>();
                var           givenNameMap = await GetGivenNames(dialogContext);

                var surnameMap = await GetSurnames(dialogContext);

                var commonWords = defaultCommonWords.Value;
                var entityTypes = EntityTypes.GetValue(dialogContext.State);
                foreach (JObject entity in entities.Where(e => entityTypes.Contains(e.Type)).Select(e => JObject.FromObject(e, Serializer)))
                {
                    text = ObjectPath.GetPathValue <string>(entity, "text");
                    if (!string.IsNullOrEmpty(text))
                    {
                        var   tokens    = TokenUtils.GetTokens(text);
                        Token prevToken = null;

                        foreach (var token in tokens)
                        {
                            if (prevToken?.Text == "'" && token.Text == "s")
                            {
                                continue;
                            }

                            string possibleGivenName = token.Text;

                            // if it starts with Cap letter and has no other cap letters, then it is highly likely it's a name
                            bool isNamePattern = char.IsUpper(token.Text[0]) &&
                                                 token.Text.Where(c => char.IsUpper(c)).Count() == 1;

                            if (givenNameMap.TryGetValue(possibleGivenName, out string gender))
                            {
                                // if it is not a common word, or it is name pattern
                                if (isNamePattern || !commonWords.Contains(possibleGivenName))
                                {
                                    dynamic givenName = JObject.FromObject(entity, Serializer);
                                    givenName.type              = "givenName";
                                    givenName.start             = token.StartOffset;
                                    givenName.end               = token.EndOffset;
                                    givenName.text              = possibleGivenName;
                                    givenName.source            = entity;
                                    givenName.resolution        = new JObject();
                                    givenName.resolution.value  = possibleGivenName;
                                    givenName.resolution.gender = gender;
                                    var newEntity = ((JObject)givenName).ToObject <Entity>();
                                    newEntities.Add(newEntity);
                                    givenNames.Add(newEntity);
                                }
                            }

                            // if any of the surname parts are a surname, then it's probably a hyphenated surname
                            string possibleSurname = token.Text;
                            var    parts           = possibleSurname.Split('-');
                            if (parts.Any(part => surnameMap.Contains(part)))
                            {
                                // if it is not a common word, or it is name pattern
                                if (isNamePattern || !commonWords.Contains(possibleGivenName))
                                {
                                    dynamic surname = JObject.FromObject(entity, Serializer);
                                    surname.type             = "surname";
                                    surname.start            = token.StartOffset;
                                    surname.end              = token.EndOffset;
                                    surname.source           = entity;
                                    surname.text             = token.Text;
                                    surname.resolution       = new JObject();
                                    surname.resolution.value = token.Text;
                                    var newEntity = ((JObject)surname).ToObject <Entity>();
                                    newEntities.Add(newEntity);
                                    surnames.Add(newEntity);
                                }
                            }

                            prevToken = token;
                        }
                    }
                }

                foreach (var givenName in givenNames)
                {
                    var surname = surnames.Where(sn => (int)sn.Properties["start"] == (int)givenName.Properties["end"] + 1).FirstOrDefault();
                    if (surname != null)
                    {
                        dynamic fullName = new JObject();
                        fullName.type                 = "fullName";
                        fullName.text                 = $"{givenName.Properties["text"]} {surname.Properties["text"]}";
                        fullName.start                = (int)givenName.Properties["start"];
                        fullName.end                  = (int)surname.Properties["end"];
                        fullName.resolution           = new JObject();
                        fullName.resolution.givenName = JObject.FromObject(givenName);
                        fullName.resolution.surname   = JObject.FromObject(surname);
                        fullName.resolution.value     = fullName.text;
                        newEntities.Add(((JObject)fullName).ToObject <Entity>());
                    }
                }
            }

            return(newEntities);
        }