void Downloader_PackagesChanged(object sender, EventArgs e)
        {
            try
            {
                Trace.TraceInformation("Autoregistrator packages changed");
                foreach (var ver in Downloader.PackageDownloader.Repositories.SelectMany(x => x.VersionsByTag.Keys))
                {
                    if (ver == "zk:stable" || ver == "zk:test")
                    {
                        Downloader.GetResource(DownloadType.MOD, ver)?.WaitHandle.WaitOne();
                    }
                }

                var waiting = false;
                do
                {
                    var downs = Downloader.Downloads.ToList().Where(x => x.IsComplete == null && !x.IsAborted).ToList();
                    if (downs.Any())
                    {
                        waiting = true;
                        var d = downs.First();
                        Trace.TraceInformation("Autoregistrator Waiting for: {0} - {1} {2}", d.Name, d.TotalProgress, d.TimeRemaining);
                    } else waiting = false;
                    if (waiting) Thread.Sleep(10000);
                } while (waiting);
                
                Trace.TraceInformation("Autoregistrator rescanning");
                Scanner.Rescan();

                do
                {
                    if (Scanner.GetWorkCost() > 0)
                    {
                        waiting = true;
                        Trace.TraceInformation("Autoregistrator Waiting for scanner: {0}", Scanner.GetWorkCost());
                    }
                    else waiting = false;
                    if (waiting) Thread.Sleep(10000);
                } while (waiting);


                Trace.TraceInformation("Autoregistrator waiting done");

                UpdateRapidTagsInDb();

                Trace.TraceInformation("Autoregistrator rapid tags updated");


                lock (Locker)
                {
                    foreach (var id in
                        new ZkDataContext(false).Missions.Where(x => !x.IsScriptMission && x.ModRapidTag != "" && !x.IsDeleted)
                            .Select(x => x.MissionID)
                            .ToList())
                    {
                        using (var db = new ZkDataContext(false))
                        {
                            var mis = db.Missions.Single(x => x.MissionID == id);
                            try
                            {
                                if (!string.IsNullOrEmpty(mis.ModRapidTag))
                                {
                                    var latestMod = Downloader.PackageDownloader.GetByTag(mis.ModRapidTag);
                                    if (latestMod != null && (mis.Mod != latestMod.InternalName || !mis.Resources.Any()))
                                    {
                                        mis.Mod = latestMod.InternalName;
                                        Trace.TraceInformation("Autoregistrator Updating mission {0} {1} to {2}", mis.MissionID, mis.Name, mis.Mod);
                                        var mu = new MissionUpdater();

                                        mis.Revision++;

                                        mu.UpdateMission(db, mis, Scanner);
                                        db.SaveChanges();
                                    }

                                }


                            }
                            catch (Exception ex)
                            {
                                Trace.TraceError("Autoregistrator Failed to update mission {0}: {1}", mis.MissionID, ex);
                            }
                        }
                    }

                    try
                    {
                        var newName = Downloader.PackageDownloader.GetByTag("zk:stable").InternalName;
                        if (lastStableVersion != newName)
                        {
                            Trace.TraceInformation("Autoregistrator Generating steam stable package");
                            lastStableVersion = newName;
                            var pgen = new SteamDepotGenerator(sitePath,
                                Path.GetFullPath(Path.Combine(sitePath, "..", "steamworks", "tools", "ContentBuilder", "content")));
                            pgen.Generate();
                            pgen.RunBuild();
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Autoregistrator Error building steam package: {0}", ex);
                    }
                }

                Trace.TraceInformation("Autoregistrator all done");
            }
            catch (Exception ex)
            {
                Trace.TraceError("Autoregistrator Error updating packages: {0}", ex);
            }
        }
        static void Downloader_PackagesChanged(object sender, EventArgs e)
        {
            foreach (var ver in Downloader.PackageDownloader.Repositories.SelectMany(x => x.VersionsByTag.Keys)) {
                if (ver.EndsWith(":test") || ver.EndsWith(":latest")) {
                    if (!Downloader.PackageDownloader.SelectedPackages.Contains(ver))
                    {
                        Trace.TraceInformation("Selecting package: {0}",ver);
                        Downloader.PackageDownloader.SelectPackage(ver);
                        Downloader.GetResource(DownloadType.MOD, ver);
                    }

                }
            }

            var waiting = false;
            do
            {
                var downs = Downloader.Downloads.ToList().Where(x => x.IsComplete == null && !x.IsAborted).ToList();
                if (downs.Any())
                {
                    waiting = true;
                    var d = downs.First();
                    Trace.TraceInformation("Waiting for: {0} - {1} {2}", d.Name, d.TotalProgress, d.TimeRemaining);
                } else if (Scanner.GetWorkCost() > 0) {
                    waiting = true;
                    Trace.TraceInformation("Waiting for scanner: {0}", Scanner.GetWorkCost());
                }
                else waiting = false;
                if (waiting) Thread.Sleep(10000);
            } while (waiting);



            lock (Locker)
            {
                foreach (var id in new ZkDataContext(false).Missions.Where(x => !x.IsScriptMission && x.ModRapidTag != "" && !x.IsDeleted).Select(x=>x.MissionID).ToList())
                {
                    using (var db = new ZkDataContext(false))
                    {
                        var mis = db.Missions.Single(x => x.MissionID == id);
                        try
                        {
                            if (!string.IsNullOrEmpty(mis.ModRapidTag))
                            {
                                var latestMod = Downloader.PackageDownloader.GetByTag(mis.ModRapidTag);
                                if (latestMod != null && mis.Mod != latestMod.InternalName)
                                {
                                    mis.Mod = latestMod.InternalName;
                                    Trace.TraceInformation("Updating mission {0} {1} to {2}", mis.MissionID, mis.Name, mis.Mod);
                                    var mu = new MissionUpdater();
                                    Mod modInfo = null;
                                    Scanner.MetaData.GetMod(mis.NameWithVersion, m => { modInfo = m; }, (er) => { });
                                    mis.Revision++;
                                    mu.UpdateMission(db, mis, modInfo);
                                    db.SubmitChanges();
                                }

                            }


                        }
                        catch (Exception ex)
                        {
                            Trace.TraceError("Failed to update mission {0}: {1}", mis.MissionID, ex);
                        }
                    }
                }
            }
        }
	    public void SendMission(Mission mission, List<MissionSlot> slots, string author, string password, Mod modInfo)
		{
            if (mission == null) throw new ApplicationException("Mission is null");

			Account acc = null;
			var db = new ZkDataContext();
			if (Debugger.IsAttached) acc = db.Accounts.SingleOrDefault(x => x.Name == "Testor303");
			else acc = AuthServiceClient.VerifyAccountPlain(author, password);

		    if (acc == null)
		    {
                Trace.TraceWarning("Invalid login attempt for {0}", author);
                System.Threading.Thread.Sleep(new Random().Next(2000));
                throw new ApplicationException("Cannot verify user account");
		    }


            Mission prev = db.Missions.SingleOrDefault(x => x.MissionID == mission.MissionID || (x.Name == mission.Name && x.AccountID == acc.AccountID)); // previous mission by id or name + account
			if (prev == null && db.Missions.Any(x =>x.Name == mission.Name)) throw new ApplicationException("Mission name must be unique");
			var map = db.Resources.SingleOrDefault(x => x.InternalName == mission.Map && x.TypeID == ZkData.ResourceType.Map);
			if (map == null) throw new ApplicationException("Map name is unknown");
			var mod = db.Resources.SingleOrDefault(x => x.InternalName == mission.Mod && x.TypeID == ZkData.ResourceType.Mod);
			if (mod == null) throw new ApplicationException("Mod name is unknown");
			//if (db.Resources.Any(x => x.InternalName == mission.Name && x.MissionID != null)) throw new ApplicationException("Name already taken by other mod/map");

            modInfo.MissionMap = mission.Map;

			if (prev != null)
			{
				if (prev.AccountID != acc.AccountID && !acc.IsZeroKAdmin) throw new ApplicationException("Invalid author or password");
				prev.Description = mission.Description;
                prev.DescriptionStory = mission.DescriptionStory;
				prev.Mod = mission.Mod;
				prev.Map = mission.Map;
				prev.Name = mission.Name;
				prev.ScoringMethod = mission.ScoringMethod;
				prev.ModRapidTag = mission.ModRapidTag;
				prev.ModOptions = mission.ModOptions;
				prev.Image = mission.Image;
				prev.MissionEditorVersion = mission.MissionEditorVersion;
				prev.SpringVersion = mission.SpringVersion;
				prev.Revision++;
				prev.Mutator = mission.Mutator;
                prev.ForumThread.Title = mission.Name;
				mission = prev;
			}
			else
			{
				mission.CreatedTime = DateTime.UtcNow;
                mission.ForumThread = new ForumThread() { Title = mission.Name, ForumCategory = db.ForumCategories.FirstOrDefault(x=>x.ForumMode==ForumMode.Missions), CreatedAccountID = acc.AccountID, LastPostAccountID= acc.AccountID };
                mission.ForumThread.UpdateLastRead(acc.AccountID, true);
				db.Missions.InsertOnSubmit(mission);
			}
			mission.AccountID = acc.AccountID;
			mission.Script = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => { return string.Format("GameType={0};", mission.NameWithVersion); });
			mission.MinHumans = slots.Count(x => x.IsHuman && x.IsRequired);
			mission.MaxHumans = slots.Count(x => x.IsHuman);
			mission.ModifiedTime = DateTime.UtcNow;
			mission.IsDeleted = true;
			mission.IsCoop = slots.Where(x => x.IsHuman).GroupBy(x => x.AllyID).Count() == 1;

	        db.SaveChanges();

	        var updater = new MissionUpdater();
            updater.UpdateMission(db, mission, modInfo);

			mission.IsDeleted = false;
	        db.SaveChanges();
		}
        private void UpdateMissions()
        {
            foreach (var id in
                new ZkDataContext(false).Missions.Where(x => !x.IsScriptMission && (x.ModRapidTag != "") && !x.IsDeleted).Select(x => x.MissionID).ToList())
                using (var db = new ZkDataContext(false))
                {
                    var mis = db.Missions.Single(x => x.MissionID == id);
                    try
                    {
                        if (!string.IsNullOrEmpty(mis.ModRapidTag))
                        {
                            var latestMod = Downloader.PackageDownloader.GetByTag(mis.ModRapidTag);
                            if ((latestMod != null) && ((mis.Mod != latestMod.InternalName) || !mis.Resources.Any()))
                            {
                                mis.Mod = latestMod.InternalName;
                                Trace.TraceInformation("Autoregistrator Updating mission {0} {1} to {2}", mis.MissionID, mis.Name, mis.Mod);
                                var mu = new MissionUpdater();

                                mis.Revision++;

                                mu.UpdateMission(db, mis, UnitSyncer.Paths, UnitSyncer.Engine);
                                db.SaveChanges();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Autoregistrator Failed to update mission {0}: {1}", mis.MissionID, ex);
                    }
                }
        }