context: using System;
  using System.Collections.Generic;
  using System.ComponentModel.Composition;
  using System.IO;
  using System.Linq;
  using System.Net.Http;
  using System.Net.Http.Headers;
  using System.Reactive.Concurrency;
  using System.Reactive.Linq;
  using System.Threading;
  using System.Threading.Tasks;
  using GitCommands.Utils;
  using GitUI;
  using GitUIPluginInterfaces;
  using GitUIPluginInterfaces.BuildServerIntegration;
  using JetBrains.Annotations;
  using Newtonsoft.Json.Linq;
  
  namespace AppVeyorIntegration
  {
      [MetadataAttribute]
      [AttributeUsage(AttributeTargets.Class)]
      public class AppVeyorIntegrationMetadata : BuildServerAdapterMetadataAttribute
      {
          public AppVeyorIntegrationMetadata(string buildServerType)
              : base(buildServerType)
          {
          }
  
          public override string CanBeLoaded
          {
              get
              {
                  if (EnvUtils.IsNet4FullOrHigher())
                  {
                      return null;
                  }
  
                  return ".Net 4 full framework required";
              }
          }
      }
  
      [Export(typeof(IBuildServerAdapter))]
      [AppVeyorIntegrationMetadata(PluginName)]
      [PartCreationPolicy(CreationPolicy.NonShared)]
      internal class AppVeyorAdapter : IBuildServerAdapter
      {
          public const string PluginName = "AppVeyor";
          private const uint ProjectsToRetrieveCount = 25;
          private const string WebSiteUrl = "https://ci.appveyor.com";
          private const string ApiBaseUrl = WebSiteUrl + "/api/projects/";
  
          private IBuildServerWatcher _buildServerWatcher;
  
          private HttpClient _httpClientAppVeyor;
  
          private List<AppVeyorBuildInfo> _allBuilds = new List<AppVeyorBuildInfo>();
          private HashSet<ObjectId> _fetchBuilds;
          private string _accountToken;
          private static readonly Dictionary<string, Project> Projects = new Dictionary<string, Project>();
          private Func<ObjectId, bool> _isCommitInRevisionGrid;
          private bool _shouldLoadTestResults;
  
          public void Initialize(
              IBuildServerWatcher buildServerWatcher,
              ISettingsSource config,
              Func<ObjectId, bool> isCommitInRevisionGrid = null)
          {
              if (_buildServerWatcher != null)
              {
                  throw new InvalidOperationException("Already initialized");
              }
  
              _buildServerWatcher = buildServerWatcher;
              _isCommitInRevisionGrid = isCommitInRevisionGrid;
              var accountName = config.GetString("AppVeyorAccountName", null);
              _accountToken = config.GetString("AppVeyorAccountToken", null);
              var projectNamesSetting = config.GetString("AppVeyorProjectName", null);
              if (accountName.IsNullOrWhiteSpace() && projectNamesSetting.IsNullOrWhiteSpace())
              {
                  return;
              }
  
              _shouldLoadTestResults = config.GetBool("AppVeyorLoadTestsResults", false);
  
              _fetchBuilds = new HashSet<ObjectId>();
  
              _httpClientAppVeyor = GetHttpClient(WebSiteUrl, _accountToken);
  
              var useAllProjects = string.IsNullOrWhiteSpace(projectNamesSetting);
              string[] projectNames = null;
              if (!useAllProjects)
              {
                  projectNames = _buildServerWatcher.ReplaceVariables(projectNamesSetting)
                      .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
              }
  
              if (Projects.Count == 0 ||
                  (!useAllProjects && Projects.Keys.Intersect(projectNames).Count() != projectNames.Length))
              {
                  Projects.Clear();
                  if (_accountToken.IsNullOrWhiteSpace())
                  {
                      FillProjectsFromSettings(accountName, projectNames);
                  }
                  else
                  {
                      if (accountName.IsNullOrWhiteSpace())
                      {
                          return;
                      }
  
                      ThreadHelper.JoinableTaskFactory.Run(
                          async () =>
                          {
                              var result = await GetResponseAsync(_httpClientAppVeyor, ApiBaseUrl, CancellationToken.None).ConfigureAwait(false);
  
                              if (result.IsNullOrWhiteSpace())
                              {
                                  return;
                              }
  
                              var projects = JArray.Parse(result);
                              foreach (var project in projects)
                              {
                                  var projectId = project["slug"].ToString();
                                  projectId = accountName.Combine("/", projectId);
                                  var projectName = project["name"].ToString();
                                  var projectObj = new Project
                                  {
                                      Name = projectName,
                                      Id = projectId,
                                      QueryUrl = BuildQueryUrl(projectId)
                                  };
  
                                  if (useAllProjects || projectNames.Contains(projectObj.Name))
                                  {
                                      Projects.Add(projectObj.Name, projectObj);
                                  }
                              }
                          });
                  }
              }
  
              var builds = Projects.Where(p => useAllProjects || projectNames.Contains(p.Value.Name)).Select(p => p.Value);
              _allBuilds =
                  FilterBuilds(builds.SelectMany(project => QueryBuildsResults(project)));
          }
  
          private static void FillProjectsFromSettings(string accountName, [InstantHandle] IEnumerable<string> projectNames)
          {
              foreach (var projectName in projectNames)
              {
                  var projectId = accountName.Combine("/", projectName);
                  if (!Projects.ContainsKey(projectName))
                  {
                      Projects.Add(projectName, new Project
                      {
                          Name = projectName,
                          Id = projectId,
                          QueryUrl = BuildQueryUrl(projectId)
                      });
                  }
              }
          }
  
          private static HttpClient GetHttpClient(string baseUrl, string accountToken)
          {
              var httpClient = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true })
              {
                  Timeout = TimeSpan.FromMinutes(2),
                  BaseAddress = new Uri(baseUrl, UriKind.Absolute),
              };
              if (accountToken.IsNotNullOrWhitespace())
              {
                  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accountToken);
              }
  
              return httpClient;
          }
  
          private static string BuildQueryUrl(string projectId)
          {
              return ApiBaseUrl + projectId + "/history?recordsNumber=" + ProjectsToRetrieveCount;
          }
  
          internal class Project
          {
              public string Name;
              public string Id;
              public string QueryUrl;
          }
  
          private string BuildPullRequetUrl(string repositoryType, string repositoryName, string pullRequestId)
          {
              switch (repositoryType.ToLowerInvariant())
              {
                  case "bitbucket":
                      return $"https://bitbucket.org/{repositoryName}/pull-requests/{pullRequestId}";
                  case "github":
                      return $"https://github.com/{repositoryName}/pull/{pullRequestId}";
                  case "gitlab":
                      return $"https://gitlab.com/{repositoryName}/merge_requests/{pullRequestId}";
                  case "vso":
                  case "git":
                  default:
                      return null;
              }
          }
  
          private IEnumerable<AppVeyorBuildInfo> QueryBuildsResults(Project project)
          {
              try
              {
                  return ThreadHelper.JoinableTaskFactory.Run(
                      async () =>
                      {
                          var result = await GetResponseAsync(_httpClientAppVeyor, project.QueryUrl, CancellationToken.None).ConfigureAwait(false);
  
                          return ExtractBuildInfo(project, result);
                      });
              }
              catch
              {
                  return Enumerable.Empty<AppVeyorBuildInfo>();
              }
          }
  
          internal IEnumerable<AppVeyorBuildInfo> ExtractBuildInfo(Project project, string result)
          {
              if (string.IsNullOrWhiteSpace(result))
              {
                  return Enumerable.Empty<AppVeyorBuildInfo>();
              }
  
              var content = JObject.Parse(result);
  
              var projectData = content["project"];
  
gt:             var repositoryName = projectData["repositoryName"];