/// <summary>
        /// This event could be raised from multiple threads. Only perform thread-safe operations
        /// </summary>
        private void PackageRestoreManager_PackageRestored(object sender, PackageRestoredEventArgs args)
        {
            if (Token.IsCancellationRequested)
            {
                _canceled = true;
                return;
            }

            if (args.Restored)
            {
                var packageIdentity = args.Package;
                Interlocked.Increment(ref CurrentCount);

                ThreadHelper.JoinableTaskFactory.RunAsync(async delegate
                {
                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                    var progressData = new ThreadedWaitDialogProgressData(string.Format(CultureInfo.CurrentCulture,
                                                                                        Resources.RestoredPackage,
                                                                                        packageIdentity),
                                                                          string.Empty,
                                                                          string.Empty,
                                                                          isCancelable: true,
                                                                          currentStep: CurrentCount,
                                                                          totalSteps: TotalCount);
                    ThreadedWaitDialogProgress.Report(progressData);
                });
            }
        }
        private void LogToVS(VerbosityLevel verbosityLevel, string message)
        {
            if (Token.IsCancellationRequested)
            {
                // If an operation is canceled, don't log anything, simply return
                // And, show a single message gets shown in the summary that package restore has been canceled
                // Do not report it as separate errors
                _canceled = true;
                return;
            }

            // If the verbosity level of message is worse than VerbosityLevel.Normal, that is,
            // VerbosityLevel.Detailed or VerbosityLevel.Diagnostic, AND,
            // _msBuildOutputVerbosity is lesser than verbosityLevel; do nothing
            if (verbosityLevel > VerbosityLevel.Normal && _msBuildOutputVerbosity < (int)verbosityLevel)
            {
                return;
            }

            ThreadHelper.JoinableTaskFactory.Run(async delegate
            {
                // Switch to main thread to update the progress dialog, output window or error list window
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                // Only show messages with VerbosityLevel.Normal. That is, info messages only.
                // Do not show errors, warnings, verbose or debug messages on the progress dialog
                // Avoid showing indented messages, these are typically not useful for the progress dialog since
                // they are missing the context of the parent text above it
                if (verbosityLevel == VerbosityLevel.Normal && message.Length == message.TrimStart().Length)
                {
                    // When both currentStep and totalSteps are 0, we get a marquee on the dialog
                    var progressData = new ThreadedWaitDialogProgressData(message,
                                                                          string.Empty,
                                                                          string.Empty,
                                                                          isCancelable: true,
                                                                          currentStep: 0,
                                                                          totalSteps: 0);

                    // Update the progress dialog
                    ThreadedWaitDialogProgress.Report(progressData);
                }

                // Write to the output window. Based on _msBuildOutputVerbosity, the message may or may not
                // get shown on the output window. Default is VerbosityLevel.Minimal
                WriteLine(verbosityLevel, message);

                // VerbosityLevel.Quiet corresponds to ILogger.LogError, and,
                // VerbosityLevel.Minimal corresponds to ILogger.LogWarning
                // In these 2 cases, we add an error or warning to the error list window
                if (verbosityLevel == VerbosityLevel.Quiet || verbosityLevel == VerbosityLevel.Minimal)
                {
                    MessageHelper.ShowError(_errorListProvider,
                                            verbosityLevel == VerbosityLevel.Quiet ? TaskErrorCategory.Error : TaskErrorCategory.Warning,
                                            TaskPriority.High,
                                            message,
                                            hierarchyItem: null);
                }
            });
        }