<commit_before>﻿using System;
using System.Collections.Generic;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;

namespace DisplayGroups
{
    internal class Program
    {


        private static void Main(string[] args)
        {
            IIdentityManagementService ims;
            TeamFoundationIdentity[] memberIdentities;
            var membershipGroups = new List<TeamFoundationIdentity>();
            var allIdentities = new Dictionary<IdentityDescriptor, TeamFoundationIdentity>(IdentityDescriptorComparer.Instance);

            if (args.Length == 0)
            {
                ShowArguments();
                return;
            }

            var address = args[0];

            var startTime = DateTime.Now;

            var tfs =
                TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
                    TfsTeamProjectCollection.GetFullyQualifiedUriForName(address));
            ims = tfs.GetService<IIdentityManagementService>();

            // Get expanded membership of the Valid Users group, which is all identities in this host
            var group = ims.ReadIdentity(GroupWellKnownDescriptors.EveryoneGroup, MembershipQuery.Expanded,
                ReadIdentityOptions.None);

            // If total membership exceeds batch size limit for Read, break it up
            var batchSizeLimit = 100000;

            if (group.Members.Length > batchSizeLimit)
            {
                BatchUpMembershipThatExceedsSizeLimit(@group, batchSizeLimit, ims, membershipGroups, allIdentities);
            }
            else
            {
                memberIdentities = ims.ReadIdentities(group.Members, MembershipQuery.Direct, ReadIdentityOptions.None);
                SortIdentities(memberIdentities, membershipGroups, allIdentities);
            }

            // Now output groups and their members. We have to call Read just once more, 
            // to get direct membership of Valid Users group
            group = ims.ReadIdentity(GroupWellKnownDescriptors.EveryoneGroup, MembershipQuery.Direct,
                ReadIdentityOptions.None);

            Write(group, allIdentities);

            foreach (var identity in membershipGroups)
            {
                Write(identity, allIdentities);
            }

            Console.WriteLine("======= Finished reading {0} identities in {1} minutes", allIdentities.Count,
                (DateTime.Now - startTime).TotalMinutes);
        }

        private static void BatchUpMembershipThatExceedsSizeLimit(TeamFoundationIdentity @group, int batchSizeLimit,
            IIdentityManagementService ims, List<TeamFoundationIdentity> membershipGroups, Dictionary<IdentityDescriptor, TeamFoundationIdentity> allIdentities)
        {
            var batchNum = 0;
            var remainder = @group.Members.Length;
            var descriptors = new IdentityDescriptor[batchSizeLimit];
            TeamFoundationIdentity[] memberIdentities;

            while (remainder > 0)
            {
                var startAt = batchNum*batchSizeLimit;
                var length = batchSizeLimit;
                if (length > remainder)
                {
                    length = remainder;
                    descriptors = new IdentityDescriptor[length];
                }

                Array.Copy(@group.Members, startAt, descriptors, 0, length);
                memberIdentities = ims.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None);
                SortIdentities(memberIdentities, membershipGroups, allIdentities);
                remainder -= length;
            }
        }

        private static void ShowArguments()
        {
            Console.WriteLine("DisplayGroups [collection]");
            Console.WriteLine("Example: DisplayGroups.exe https://myaccount.visualstudio.com/DefaultCollection");
        }

        private static void SortIdentities(TeamFoundationIdentity[] identities, List<TeamFoundationIdentity> membershipGroups,
            Dictionary<IdentityDescriptor, TeamFoundationIdentity> allIdentities)
        {
            foreach (var identity in identities)
            {
                allIdentities.Add(identity.Descriptor, identity);

                if (identity.IsContainer)
                {
                    membershipGroups.Add(identity);
                }
            }
        }

        private static void Write(TeamFoundationIdentity group, Dictionary<IdentityDescriptor, TeamFoundationIdentity> allIdentities)
        {
            // Output this group's membership<commit_msg>More minor refactoring and cleanup.<commit_after>﻿using System;
using System.Collections.Generic;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;

namespace DisplayGroups
{
    public class Program
    {

        private static void Main(string[] args)
        {
            var membershipGroups = new List<TeamFoundationIdentity>();
            var allIdentities = new Dictionary<IdentityDescriptor, TeamFoundationIdentity>(IdentityDescriptorComparer.Instance);

            if (args.Length == 0)
            {
                ShowArguments();
                return;
            }

            var address = args[0];

            var startTime = DateTime.Now;

            var ims = GetIdentityManagementService(address);

            // Get expanded membership of the Valid Users group, which is all identities in this host
            var validUsersGroupMembers = ims.ReadIdentity(GroupWellKnownDescriptors.EveryoneGroup, MembershipQuery.Expanded,
                ReadIdentityOptions.None);

            // If total membership exceeds batch size limit for Read, break it up
            const int batchSizeLimit = 100000;

            if (validUsersGroupMembers.Members.Length > batchSizeLimit)
            {
                BatchUpMembershipThatExceedsSizeLimit(validUsersGroupMembers, batchSizeLimit, ims, membershipGroups, allIdentities);
            }
            else
            {
                var memberIdentities = ims.ReadIdentities(validUsersGroupMembers.Members, MembershipQuery.Direct, ReadIdentityOptions.None);
                SortIdentities(memberIdentities, membershipGroups, allIdentities);
            }

            // Now output groups and their members. We have to call Read just once more, 
            // to get direct membership of Valid Users group
            validUsersGroupMembers = ims.ReadIdentity(GroupWellKnownDescriptors.EveryoneGroup, MembershipQuery.Direct,
                ReadIdentityOptions.None);

            WriteGroupMembers(validUsersGroupMembers, allIdentities);

            foreach (var identity in membershipGroups)
            {
                WriteGroupMembers(identity, allIdentities);
            }

            Console.WriteLine("======= Finished reading {0} identities in {1} minutes", allIdentities.Count,
                (DateTime.Now - startTime).TotalMinutes);
        }

        private static IIdentityManagementService GetIdentityManagementService(string address)
        {
            var tfs =
                TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
                    TfsTeamProjectCollection.GetFullyQualifiedUriForName(address));
            var ims = tfs.GetService<IIdentityManagementService>();
            return ims;
        }

        private static void BatchUpMembershipThatExceedsSizeLimit(TeamFoundationIdentity @group, int batchSizeLimit,
            IIdentityManagementService ims, List<TeamFoundationIdentity> membershipGroups, Dictionary<IdentityDescriptor, TeamFoundationIdentity> allIdentities)
        {
            var batchNum = 0;
            var remainder = @group.Members.Length;
            var descriptors = new IdentityDescriptor[batchSizeLimit];
            TeamFoundationIdentity[] memberIdentities;

            while (remainder > 0)
            {
                var startAt = batchNum*batchSizeLimit;
                var length = batchSizeLimit;
                if (length > remainder)
                {
                    length = remainder;
                    descriptors = new IdentityDescriptor[length];
                }

                Array.Copy(@group.Members, startAt, descriptors, 0, length);
                memberIdentities = ims.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None);
                SortIdentities(memberIdentities, membershipGroups, allIdentities);
                remainder -= length;
            }
        }

        private static void ShowArguments()
        {
            Console.WriteLine("DisplayGroups [collection]");
            Console.WriteLine("Example: DisplayGroups.exe https://myaccount.visualstudio.com/DefaultCollection");
        }

        private static void SortIdentities(TeamFoundationIdentity[] identities, List<TeamFoundationIdentity> membershipGroups,
            Dictionary<IdentityDescriptor, TeamFoundationIdentity> allIdentities)
        {
            foreach (var identity in identities)
            {
                allIdentities.Add(identity.Descriptor, identity);

                if (identity.IsContainer)
                {
                    membershipGroups.Add(identity);
                }
            }
        }

        private static void WriteGroupMembers(TeamFoundationIdentity group, Dictionary<IdentityDescriptor, TeamFoundationIdentity> allIdentities)
        {
            // Output this group's membership
{'fraction_non_alphanumeric': 0.06840016708437761, 'fraction_numerical': 0.0027151211361737676, 'mean_word_length': 2.1817275747508305, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 25, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2231162', 'n_tokens_mistral': 2190, 'n_tokens_neox': 2059, 'n_words': 502}