/// <summary>
        /// Perform and update
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static bool PerformUpdate(PackageInfo info)
        {
            var upd = FetchUpdate(info);
            if (!String.IsNullOrEmpty(upd))
            {
                var plugins = InstallUpdate(upd);

                foreach (var plg in plugins)
                {
                    var newPlugin = PluginManager.LoadPluginFromPath(plg);
                    if (newPlugin != null)
                    {
                        //Determine if we must replace an existing or enable a new plugin
                        var oldPlugin = PluginManager.GetPlugin(newPlugin.Name);
                        if (oldPlugin != null)
                        {
                            if (PluginManager.ReplacePlugin(oldPlugin, newPlugin))
                            {
                                ProgramLog.Admin.Log("Plugin {0} has been replaced.", oldPlugin.Name, Color.DodgerBlue);
                            }
                            else if (oldPlugin.IsDisposed)
                            {
                                ProgramLog.Admin.Log("Replacement of plugin {0} failed, it has been unloaded.", oldPlugin.Name, Color.DodgerBlue);
                            }
                            else
                            {
                                ProgramLog.Admin.Log("Replacement of plugin {0} failed, old instance kept.", oldPlugin.Name, Color.DodgerBlue);
                            }

                            break;
                        }

                        PluginManager.RegisterPlugin(newPlugin);
                    }
                }

                return plugins != null && plugins.Length > 0;
            }

            return false;
        }
        /// <summary>
        /// Get all available updates or check for a specific package update.
        /// </summary>
        /// <param name="packageName"></param>
        /// <returns></returns>
        public static PackageInfo[] GetAvailableUpdate(string packageName = null, bool updateOnly = true)
        {
            if (String.IsNullOrEmpty(packageName))
            {
                var info = new PackageInfo[PluginManager.PluginCount];

                var pending = 0;
                foreach (var plg in PluginManager.EnumeratePlugins)
                {
                    var res = GetUpdateInfo(plg.Name, plg.Version);
                    if (res != null) info[pending++] = res;
                }

                if (pending != info.Length)
                {
                    System.Array.Resize(ref info, pending);
                }

                return info;
            }
            else
            {
                string current = null, lowered = packageName.ToLower();
                foreach (var plg in PluginManager.EnumeratePlugins)
                {
                    if (plg.Name.ToLower() == lowered)
                    {
                        current = plg.Version;
                        break;
                    }
                }

                if (updateOnly && String.IsNullOrEmpty(current))
                {
                    throw new RepositoryError("No installed package by name {0}", packageName);
                }

                if (!updateOnly && !String.IsNullOrEmpty(current))
                {
                    throw new RepositoryError("{0} is already installed", packageName);
                }

                var res = GetUpdateInfo(packageName, current);
                if (res != null) return new PackageInfo[] { res };
            }

            return null;
        }
        private static string FetchUpdate(PackageInfo info)
        {
            var tmp = Path.Combine(Environment.CurrentDirectory, ".repo");
            var di = new DirectoryInfo(tmp);
            if (!di.Exists)
            {
                di.Create();
                di.Attributes = FileAttributes.Hidden;
            }

            var isGitHub = System.Text.RegularExpressions.Regex.IsMatch(info.DownloadUrl, "https://api.github.com/repos/.*/.*/releases", System.Text.RegularExpressions.RegexOptions.Singleline);
            if (isGitHub)
            {
                var release = GetGitHubRelease(info.DownloadUrl);
                if (release.Assets != null && release.Assets.Length > 0)
                {
                    var saveAs = Path.Combine(tmp, release.Assets[0].FileName);
                    if (File.Exists(saveAs)) File.Delete(saveAs);
                    using (var wc = new ProgressWebClient("Downloading"))
                    {
                        var wait = new System.Threading.AutoResetEvent(false);
                        wc.DownloadFileCompleted += (s, a) =>
                        {
                            wait.Set();
                        };
                        wc.DownloadFileAsync(new Uri(release.Assets[0].DownloadUrl), saveAs);

                        wait.WaitOne();
                        return saveAs;
                    }
                }
                else throw new RepositoryError("Failed to fetch release from GitHub");
            }
            else
            {
                var fileName = info.DownloadUrl;
                var last = fileName.LastIndexOf("/");
                if (last > -1)
                {
                    fileName = fileName.Remove(0, last);
                }

                var saveAs = Path.Combine(tmp, fileName);
                if (File.Exists(saveAs)) File.Delete(saveAs);
                using (var wc = new ProgressWebClient("Downloading"))
                {
                    var wait = new System.Threading.AutoResetEvent(false);
                    wc.DownloadFileCompleted += (s, a) =>
                    {
                        wait.Set();
                    };
                    wc.DownloadFileAsync(new Uri(info.DownloadUrl), saveAs);

                    wait.WaitOne();
                    return saveAs;
                }
            }
        }