protected override void UpgradeProject(
            ref ProjectRootElement projectXml,
            ref ProjectRootElement userProjectXml,
            Action<__VSUL_ERRORLEVEL, string> log
        ) {
            Version version;

            // ToolsVersion less than 4.0 (or unspecified) is not supported, so
            // set it to 4.0.
            if (!Version.TryParse(projectXml.ToolsVersion, out version) ||
                version < new Version(4, 0)) {
                projectXml.ToolsVersion = "4.0";
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, SR.GetString(SR.UpgradedToolsVersion));
            }

            // Importing a targets file from 2.1 Beta
            var bottleImports = projectXml.Imports.Where(p => p.Project.Equals(Ptvs21BetaBottleTargets, StringComparison.OrdinalIgnoreCase)).ToList();
            var flaskImports = projectXml.Imports.Where(p => p.Project.Equals(Ptvs21BetaFlaskTargets, StringComparison.OrdinalIgnoreCase)).ToList();
            foreach (var import in bottleImports.Concat(flaskImports)) {
                import.Project = WebTargets;
            }

            if (bottleImports.Any()) {
                var globals = projectXml.PropertyGroups.FirstOrDefault() ?? projectXml.AddPropertyGroup();
                AddOrSetProperty(globals, "PythonDebugWebServerCommandArguments", "--debug $(CommandLineArguments)");
                AddOrSetProperty(globals, "PythonWsgiHandler", "{StartupModule}.wsgi_app()");
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, SR.GetString(SR.UpgradedBottleImports));
            }
            if (flaskImports.Any()) {
                var globals = projectXml.PropertyGroups.FirstOrDefault() ?? projectXml.AddPropertyGroup();
                AddOrSetProperty(globals, "PythonWsgiHandler", "{StartupModule}.wsgi_app");
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, SR.GetString(SR.UpgradedFlaskImports));
            }

            var commonPropsImports = projectXml.Imports.Where(p => p.Project.Equals(CommonProps, StringComparison.OrdinalIgnoreCase)).ToList();
            foreach (var p in commonPropsImports) {
                projectXml.RemoveChild(p);
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, SR.GetString(SR.UpgradedRemoveCommonProps));
            }
            
            if (projectXml.Imports.Count == 1 && projectXml.Imports.First().Project.Equals(CommonTargets, StringComparison.OrdinalIgnoreCase)) {
                projectXml.RemoveChild(projectXml.Imports.First());
                var group = projectXml.AddPropertyGroup();
                if (!projectXml.Properties.Any(p => p.Name == "VisualStudioVersion")) {
                    group.AddProperty("VisualStudioVersion", "10.0").Condition = "'$(VisualStudioVersion)' == ''";
                }
                group.AddProperty("PtvsTargetsFile", PtvsTargets);
                projectXml.AddImport("$(PtvsTargetsFile)").Condition = "Exists($(PtvsTargetsFile))";
                projectXml.AddImport(CommonTargets).Condition = "!Exists($(PtvsTargetsFile))";
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, SR.GetString(SR.UpgradedRemoveCommonTargets));
            }
        }
		static void RemovePropertyCompletely(ProjectRootElement project, string propertyName)
		{
			foreach (var propertyGroup in project.PropertyGroups.ToList()) {
				bool propertyRemoved = false;
				foreach (var property in propertyGroup.Properties.ToList()) {
					if (MSBuildInternals.PropertyNameComparer.Equals(property.Name, propertyName)) {
						propertyGroup.RemoveChild(property);
						propertyRemoved = true;
					}
				}
				if (propertyRemoved && propertyGroup.Children.Count() == 0)
					project.RemoveChild(propertyGroup);
			}
		}
        private static void ProcessImportsFrom21b(ProjectRootElement projectXml, Action<__VSUL_ERRORLEVEL, string> log) {
            var bottleImports = projectXml.Imports.Where(p => p.Project.Equals(Ptvs21BetaBottleTargets, StringComparison.OrdinalIgnoreCase)).ToList();
            var flaskImports = projectXml.Imports.Where(p => p.Project.Equals(Ptvs21BetaFlaskTargets, StringComparison.OrdinalIgnoreCase)).ToList();
            foreach (var import in bottleImports.Concat(flaskImports)) {
                import.Project = WebTargets;
            }

            if (bottleImports.Any()) {
                var globals = projectXml.PropertyGroups.FirstOrDefault() ?? projectXml.AddPropertyGroup();
                AddOrSetProperty(globals, "PythonDebugWebServerCommandArguments", "--debug $(CommandLineArguments)");
                AddOrSetProperty(globals, "PythonWsgiHandler", "{StartupModule}.wsgi_app()");
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, Strings.UpgradedBottleImports);
            }
            if (flaskImports.Any()) {
                var globals = projectXml.PropertyGroups.FirstOrDefault() ?? projectXml.AddPropertyGroup();
                AddOrSetProperty(globals, "PythonWsgiHandler", "{StartupModule}.wsgi_app");
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, Strings.UpgradedFlaskImports);
            }

            var commonPropsImports = projectXml.Imports.Where(p => p.Project.Equals(CommonProps, StringComparison.OrdinalIgnoreCase)).ToList();
            foreach (var p in commonPropsImports) {
                projectXml.RemoveChild(p);
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, Strings.UpgradedRemoveCommonProps);
            }

            if (projectXml.Imports.Count == 1 && projectXml.Imports.First().Project.Equals(CommonTargets, StringComparison.OrdinalIgnoreCase)) {
                projectXml.RemoveChild(projectXml.Imports.First());
                projectXml.AddImport(PtvsTargets);
                log(__VSUL_ERRORLEVEL.VSUL_INFORMATIONAL, Strings.UpgradedRemoveCommonTargets);
            }
        }