/// <summary>
        /// SORRY :( I didn't have time to put this in a service somewhere - the old packager did this all manually too
        /// </summary>
        /// <param name="pack"></param>
        protected void PerformUninstall(InstalledPackage pack)
        {
            if (pack == null)
            {
                throw new ArgumentNullException("pack");
            }

            var refreshCache = false;

            var removedTemplates       = new List <ITemplate>();
            var removedMacros          = new List <IMacro>();
            var removedContentTypes    = new List <IContentType>();
            var removedDictionaryItems = new List <IDictionaryItem>();
            var removedDataTypes       = new List <IDataTypeDefinition>();
            var removedFiles           = new List <string>();

            //Uninstall templates
            foreach (var item in pack.Data.Templates.ToArray())
            {
                int nId;
                if (int.TryParse(item, out nId) == false)
                {
                    continue;
                }
                var found = Services.FileService.GetTemplate(nId);
                if (found != null)
                {
                    removedTemplates.Add(found);
                    ApplicationContext.Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId());
                }
                pack.Data.Templates.Remove(nId.ToString());
            }

            //Uninstall macros
            foreach (var item in pack.Data.Macros.ToArray())
            {
                int nId;
                if (int.TryParse(item, out nId) == false)
                {
                    continue;
                }
                var macro = Services.MacroService.GetById(nId);
                if (macro != null)
                {
                    removedMacros.Add(macro);
                    Services.MacroService.Delete(macro);
                }
                pack.Data.Macros.Remove(nId.ToString());
            }

            //Remove Document Types
            var contentTypes       = new List <IContentType>();
            var contentTypeService = Services.ContentTypeService;

            foreach (var item in pack.Data.Documenttypes.ToArray())
            {
                int nId;
                if (int.TryParse(item, out nId) == false)
                {
                    continue;
                }
                var contentType = contentTypeService.GetContentType(nId);
                if (contentType == null)
                {
                    continue;
                }
                contentTypes.Add(contentType);
                pack.Data.Documenttypes.Remove(nId.ToString(CultureInfo.InvariantCulture));
                // refresh content cache when document types are removed
                refreshCache = true;
            }

            //Order the DocumentTypes before removing them
            if (contentTypes.Any())
            {
                //TODO: I don't think this ordering is necessary
                var orderedTypes = from contentType in contentTypes
                                   orderby contentType.ParentId descending, contentType.Id descending
                select contentType;
                removedContentTypes.AddRange(orderedTypes);
                contentTypeService.Delete(orderedTypes);
            }

            //Remove Dictionary items
            foreach (var item in pack.Data.DictionaryItems.ToArray())
            {
                int nId;
                if (int.TryParse(item, out nId) == false)
                {
                    continue;
                }
                var di = Services.LocalizationService.GetDictionaryItemById(nId);
                if (di != null)
                {
                    removedDictionaryItems.Add(di);
                    Services.LocalizationService.Delete(di);
                }
                pack.Data.DictionaryItems.Remove(nId.ToString());
            }

            //Remove Data types
            foreach (var item in pack.Data.DataTypes.ToArray())
            {
                int nId;
                if (int.TryParse(item, out nId) == false)
                {
                    continue;
                }
                var dtd = Services.DataTypeService.GetDataTypeDefinitionById(nId);
                if (dtd != null)
                {
                    removedDataTypes.Add(dtd);
                    Services.DataTypeService.Delete(dtd);
                }
                pack.Data.DataTypes.Remove(nId.ToString());
            }

            pack.Save();

            // uninstall actions
            //TODO: We should probably report errors to the UI!!
            // This never happened before though, but we should do something now
            if (pack.Data.Actions.IsNullOrWhiteSpace() == false)
            {
                try
                {
                    var actionsXml = new XmlDocument();
                    actionsXml.LoadXml("<Actions>" + pack.Data.Actions + "</Actions>");

                    LogHelper.Debug <PackageInstallController>("executing undo actions: {0}", () => actionsXml.OuterXml);

                    foreach (XmlNode n in actionsXml.DocumentElement.SelectNodes("//Action"))
                    {
                        try
                        {
                            global::umbraco.cms.businesslogic.packager.PackageAction
                            .UndoPackageAction(pack.Data.Name, n.Attributes["alias"].Value, n);
                        }
                        catch (Exception ex)
                        {
                            LogHelper.Error <PackageInstallController>("An error occurred running undo actions", ex);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error <PackageInstallController>("An error occurred running undo actions", ex);
                }
            }

            //moved remove of files here so custom package actions can still undo
            //Remove files
            foreach (var item in pack.Data.Files.ToArray())
            {
                removedFiles.Add(item.GetRelativePath());

                //here we need to try to find the file in question as most packages does not support the tilde char
                var file = IOHelper.FindFile(item);
                if (file != null)
                {
                    if (file.StartsWith("/") == false)
                    {
                        file = string.Format("/{0}", file);
                    }
                    var filePath = IOHelper.MapPath(file);

                    if (File.Exists(filePath))
                    {
                        File.Delete(filePath);
                    }
                }
                pack.Data.Files.Remove(file);
            }
            pack.Save();
            pack.Delete(Security.GetUserId());

            // create a summary of what was actually removed, for PackagingService.UninstalledPackage
            var summary = new UninstallationSummary
            {
                MetaData                   = pack.GetMetaData(),
                TemplatesUninstalled       = removedTemplates,
                MacrosUninstalled          = removedMacros,
                ContentTypesUninstalled    = removedContentTypes,
                DictionaryItemsUninstalled = removedDictionaryItems,
                DataTypesUninstalled       = removedDataTypes,
                FilesUninstalled           = removedFiles,
                PackageUninstalled         = true
            };

            // trigger the UninstalledPackage event
            PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs <UninstallationSummary>(summary, false));

            //TODO: Legacy - probably not needed
            if (refreshCache)
            {
                library.RefreshContent();
            }
            TreeDefinitionCollection.Instance.ReRegisterTrees();
            global::umbraco.BusinessLogic.Actions.Action.ReRegisterActionsAndHandlers();
        }