//if( !launchSequencerEnabled ) // return; bool areAllDepsSatisfied( AppDef appDef ) { // pokud jsou vsechny aplikace na kterych ta nase zavisi spousteny bool allDepsSatisfied = true; if (appDef.Dependencies != null) { foreach (var depName in appDef.Dependencies) { AppIdTuple depId = AppIdTuple.fromString(depName, appDef.AppIdTuple.MachineId); if (!appsState.ContainsKey(depId)) { // throw exception "Unknown dependency" throw new UnknownDependencyException(depName); } var dep = appsState[depId]; if (!dep.Initialized) { allDepsSatisfied = false; break; } } } return allDepsSatisfied; }
public IEnumerable <string> GetScriptsForEnvironment(TargetEnvironment environment) { var env = environment.ToString().ToLowerInvariant(); var modules = AppDef.Element("application") .Element("modules"); if (modules == null) { return(Enumerable.Empty <string>()); } var module = modules.Elements("module").Where( m => m.Attribute("environment").Value.ToLowerInvariant() == env); if (module == null) { return(Enumerable.Empty <string>()); } var excluded = new List <string> { "_package_start.js", "_package_end.js" }; var files = module.Elements("file") .Where(f => !excluded.Contains(f.Value.ToLowerInvariant())) .Select(f => f.Value); return(files); }
//if( !launchSequencerEnabled ) // return; bool areAllDepsSatisfied(AppDef appDef) { // pokud jsou vsechny aplikace na kterych ta nase zavisi spousteny bool allDepsSatisfied = true; if (appDef.Dependencies != null) { foreach (var depName in appDef.Dependencies) { AppIdTuple depId = AppIdTuple.fromString(depName, appDef.AppIdTuple.MachineId); if (!appsState.ContainsKey(depId)) { // throw exception "Unknown dependency" throw new UnknownDependencyException(depName); } var dep = appsState[depId]; if (!dep.Initialized) { allDepsSatisfied = false; break; } } } return(allDepsSatisfied); }
public IAppInitializedDetector create(AppDef appDef, AppState appState, int processId, XElement xml) { //if( string.IsNullOrEmpty(definitionString) ) //{ // throw new UnknownAppInitDetectorType( appDef.AppIdTuple + " <Init condition not defined>" ); //} //string name=""; //string args=""; //parseDefinitionString(definitionString, ref name, ref args); //if( !creators.ContainsKey(name) ) //{ // throw new UnknownAppInitDetectorType( definitionString ); //} //CreateDeleg cd = creators[name]; //return cd(appDef, appState, processId, args); string name = xml.Name.LocalName; CreateDeleg cd = Find(name); if (cd == null) { throw new UnknownAppInitDetectorType(name); } return(cd(appDef, appState, processId, xml)); }
public IAppInitializedDetector create(AppDef appDef, AppState appState, int processId, XElement xml) { //if( string.IsNullOrEmpty(definitionString) ) //{ // throw new UnknownAppInitDetectorType( appDef.AppIdTuple + " <Init condition not defined>" ); //} //string name=""; //string args=""; //parseDefinitionString(definitionString, ref name, ref args); //if( !creators.ContainsKey(name) ) //{ // throw new UnknownAppInitDetectorType( definitionString ); //} //CreateDeleg cd = creators[name]; //return cd(appDef, appState, processId, args); string name = xml.Name.LocalName; CreateDeleg cd = Find(name); if( cd == null ) { throw new UnknownAppInitDetectorType( name ); } return cd(appDef, appState, processId, xml); }
public void testSelectPlanAndKillApp() { var ctrlMock = new Mock <IDirigentControl>(); var appIdTuple = new AppIdTuple("m1.a"); var appDef = new AppDef() { AppIdTuple = appIdTuple }; var plan = new LaunchPlan("plan1", new List <AppDef>() { appDef }); var planRepo = new List <ILaunchPlan>() { plan }; ctrlMock.Setup(f => f.GetPlanRepo()).Returns(planRepo); //ctrlMock.Setup(f => f.SelectPlan(plan)).Verifiable(); var cmdRepo = new CommandRepository(); //cmdRepo.Register( new Commands.SelectPlan(ctrlMock.Object) ); //cmdRepo.ParseAndExecute(new List<string>() { ";SelectPlan", "plan1;", "KillApp", "m1.a1;" }); cmdRepo.ParseAndExecute(new List <string>() { "KillApp", "m1.a1;" }); ctrlMock.Verify(); //Assert.AreEqual("); }
public void testFactoryFailsForUnknownType() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var f = new AppInitializedDetectorFactory(); var d = f.create( appDef, appState, 0, XElement.Parse("<unknown>any-params</unknown>") ); }
public void testFactoryFailsForUnknownType() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var f = new AppInitializedDetectorFactory(); var d = f.create(appDef, appState, 0, XElement.Parse("<unknown>any-params</unknown>")); }
public ExitCodeInitDetector(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; try { string args = xml.Value; // " -1, 1, 2,3, 6-8 " foreach(var token in args.Split(',')) { // fill the exitCodes var trimmed = token.Trim(); Match m; m = Regex.Match( trimmed, "(-?\\d+)-(-?\\d+)" ); // "1-6" or "-4-8" or "-4--1" if (m.Success) { var lo = int.Parse(m.Groups[1].Value); var hi = int.Parse(m.Groups[2].Value); if( lo <= hi ) { for( var i = lo; i <= hi; i++ ) { exitCodes.Add(i); } } } else { m = Regex.Match( trimmed, "(-?\\d+)" ); if (m.Success) { var i = int.Parse(m.Groups[0].Value); exitCodes.Add(i); } } } // no exit codes specified?? if (exitCodes.Count == 0) { throw new InvalidAppInitDetectorArguments(Name, args); } appState.Initialized = false; // will be set to true as soon as the exit code condition is met } catch( Exception ex ) { if (ex is FormatException || ex is OverflowException) { throw new InvalidAppInitDetectorArguments(Name, xml.ToString()); } throw; } }
public ExitCodeInitDetector(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; try { string args = xml.Value; // " -1, 1, 2,3, 6-8 " foreach (var token in args.Split(',')) { // fill the exitCodes var trimmed = token.Trim(); Match m; m = Regex.Match(trimmed, "(-?\\d+)-(-?\\d+)"); // "1-6" or "-4-8" or "-4--1" if (m.Success) { var lo = int.Parse(m.Groups[1].Value); var hi = int.Parse(m.Groups[2].Value); if (lo <= hi) { for (var i = lo; i <= hi; i++) { exitCodes.Add(i); } } } else { m = Regex.Match(trimmed, "(-?\\d+)"); if (m.Success) { var i = int.Parse(m.Groups[0].Value); exitCodes.Add(i); } } } // no exit codes specified?? if (exitCodes.Count == 0) { throw new InvalidAppInitDetectorArguments(Name, args); } appState.Initialized = false; // will be set to true as soon as the exit code condition is met } catch (Exception ex) { if (ex is FormatException || ex is OverflowException) { throw new InvalidAppInitDetectorArguments(Name, xml.ToString()); } throw; } }
public AutoRestarter(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; parseXml( xml ); state = eState.WaitingForCrash; this.processId = processId; this.appDef = appDef; }
readonly double RESTART_DELAY = 5.0; // howlong to wait before restarting the app public AutoRestarter(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; parseXml(xml); state = eState.WaitingForCrash; this.processId = processId; this.appDef = appDef; }
public void testFactoryCreatesTimeOut() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var f = new AppInitializedDetectorFactory(); IAppInitializedDetector d = f.create(appDef, appState, 0, XElement.Parse("<timeout> 0.1</timeout>")); Assert.AreEqual(typeof(TimeOutInitDetector), d.GetType(), "correct detector type created"); }
public void testFactoryCreatesTimeOut() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var f = new AppInitializedDetectorFactory(); IAppInitializedDetector d = f.create( appDef, appState, 0, XElement.Parse("<timeout> 0.1</timeout>") ); Assert.AreEqual(typeof(TimeOutInitDetector), d.GetType(), "correct detector type created"); }
public void testTimeOutDetector() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var initialTicks = DateTime.UtcNow.Ticks; IAppInitializedDetector d = new TimeOutInitDetector(appDef, appState, 0, XElement.Parse("<timeout>0.1</timeout>")); Assert.AreEqual(false, d.IsInitialized, "not initialized immediately"); Thread.Sleep(100); Assert.AreEqual(true, d.IsInitialized, "initialized after time out"); }
public void testTimeOutDetector() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var initialTicks = DateTime.UtcNow.Ticks; IAppInitializedDetector d = new TimeOutInitDetector(appDef, appState, 0, XElement.Parse("<timeout>0.1</timeout>")); Assert.AreEqual(false, d.IsInitialized, "not initialized immediately"); Thread.Sleep(100); Assert.AreEqual(true, d.IsInitialized, "initialized after time out"); }
public Launcher(AppDef appDef, String rootForRelativePaths) { this.appDef = appDef; if (String.IsNullOrEmpty(rootForRelativePaths)) { RelativePathsRoot = System.IO.Directory.GetCurrentDirectory(); } else { RelativePathsRoot = rootForRelativePaths; } }
public WindowPositioner(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; //this.pos = pos; this.processId = processId; parseXml( xml ); //if( pos.Rect == System.Drawing.Rectangle.Empty ) throw new InvalidAppConfig(appDef.AppIdTuple, "WindowPos: Missing Rectangle attribute"); if( string.IsNullOrEmpty( pos.TitleRegExp )) throw new InvalidAppConfig(appDef.AppIdTuple, "WindowPos: Missing TitleRegExp atribute"); titleRegExp = new Regex( pos.TitleRegExp ); }
public Dictionary <string, string> GetDashboards() { var dashboards = AppDef.Element("application").Element("dashboards"); if (dashboards == null) { return(new Dictionary <string, string>()); } return(dashboards.Elements("dashboard").ToDictionary( db => db.Attribute("id").Value, db => db.Element("content").Value)); }
public void testDetectorSingle() { AppDef appDef = new AppDef(); AppState appState = new AppState(); appState.Started = true; appState.Running = true; IAppInitializedDetector d = new ExitCodeInitDetector(appDef, appState, 0, XElement.Parse("<timeout>1</timeout>")); Assert.AreEqual(false, d.IsInitialized, "not initialized immediately"); appState.Running = false; appState.ExitCode = 0; Assert.AreEqual(false, d.IsInitialized, "not initialized if wrong exit code"); appState.ExitCode = 1; Assert.AreEqual(true, d.IsInitialized, "initialized if correct exit code"); }
public void testDetectorSingle() { AppDef appDef = new AppDef(); AppState appState = new AppState(); appState.Started = true; appState.Running = true; IAppInitializedDetector d = new ExitCodeInitDetector(appDef, appState, 0, XElement.Parse("<timeout>1</timeout>")); Assert.AreEqual(false, d.IsInitialized, "not initialized immediately"); appState.Running = false; appState.ExitCode = 0; Assert.AreEqual(false, d.IsInitialized, "not initialized if wrong exit code"); appState.ExitCode = 1; Assert.AreEqual(true, d.IsInitialized, "initialized if correct exit code"); }
public WindowPositioner(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; //this.pos = pos; this.processId = processId; parseXml(xml); //if( pos.Rect == System.Drawing.Rectangle.Empty ) throw new InvalidAppConfig(appDef.AppIdTuple, "WindowPos: Missing Rectangle attribute"); if (string.IsNullOrEmpty(pos.TitleRegExp)) { throw new InvalidAppConfig(appDef.AppIdTuple, "WindowPos: Missing TitleRegExp atribute"); } titleRegExp = new Regex(pos.TitleRegExp); }
public void testSelectPlan() { var ctrlMock = new Mock<IDirigentControl>(); var appIdTuple = new AppIdTuple("m1.a"); var appDef = new AppDef() { AppIdTuple = appIdTuple }; var plan = new LaunchPlan("plan1", new List<AppDef>() { appDef } ); var planRepo = new List<ILaunchPlan>() { plan }; ctrlMock.Setup(f => f.GetPlanRepo()).Returns(planRepo); ctrlMock.Setup(f => f.SelectPlan(plan)).Verifiable(); var cmdRepo = new CommandRepository(); cmdRepo.Register( new Commands.SelectPlan(ctrlMock.Object) ); cmdRepo.ParseAndExecute(new List<string>() { "SelectPlan", "plan1" }); ctrlMock.Verify(); //Assert.AreEqual("); }
public WindowPoppedUpInitDetector(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; this.processId = processId; this.appDef = appDef; try { parseArgs(xml); } catch { throw new InvalidAppInitDetectorArguments(Name, xml.ToString()); } appState.Initialized = false; // will be set to true as soon as the exit code condition is met log.DebugFormat("WindowPoppedUpInitDetector: Waiting for window with titleRegExp {0}, appid {1}, pid {2}", titleRegExpString, appDef.AppIdTuple, processId); }
public WindowPoppedUpInitDetector(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; this.processId = processId; this.appDef = appDef; try { parseArgs( xml ); } catch { throw new InvalidAppInitDetectorArguments(Name, xml.ToString()); } appState.Initialized = false; // will be set to true as soon as the exit code condition is met log.DebugFormat("WindowPoppedUpInitDetector: Waiting for window with titleRegExp {0}, appid {1}, pid {2}", titleRegExpString, appDef.AppIdTuple, processId ); }
public async Task <AppDef> GetAppDef(string id) { AppDef res = new AppDef(); var op = _master.AddSynchronousOp(() => { var(appIdTuple, planName) = Tools.ParseAppIdWithPlan(id); var ad = _master.GetAppDef(appIdTuple); if (ad is null) { throw HttpException.NotFound(); } res = new AppDef(ad); }); await op.WaitAsync(); return(res); }
/// <summary> /// If the time interval from last query exceeds the separation interval of last returned app, /// returns a next app from the queue. /// </summary> /// <param name="currentTimeStamp"></param> /// <returns>null if no app to be lanched, otherwise the AppDef</returns> public AppDef GetNext(double currentTime) { AppDef res = null; if (!IsEmpty()) { double deltaSeconds = currentTime - timeOfLastLaunch; if (deltaSeconds >= lastAppSeparationInterval) { res = appQueue[0]; // remember constraints for the next one timeOfLastLaunch = currentTime; lastAppSeparationInterval = res.SeparationInterval; // remove the app returned appQueue.RemoveAt(0); } } return(res); }
//<TimeOut>2.0</TimeOut> public TimeOutInitDetector(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; this.processId = processId; this.appDef = appDef; try { var timeString = xml.Value; TimeOut = Double.Parse( timeString, CultureInfo.InvariantCulture ); } catch { throw new InvalidAppInitDetectorArguments(Name, xml.ToString()); } appState.Initialized = false; // will be set to true as soon as the exit code condition is met InitialTicks = DateTime.UtcNow.Ticks; log.DebugFormat("TimeOutInitDetector: Waiting {0} sec, appid {1}, pid {2}", TimeOut, appDef.AppIdTuple, processId ); }
public Reference(ITaskItem item) { FullPath = item.GetMetadata("FullPath"); Zip = new ZipFile(FullPath); var appdef = Zip.FirstOrDefault(ze => ze.FileName.ToLowerInvariant() == "appdef.xml"); if (appdef == null) { throw new FileNotFoundException(string.Format( "The package definition file 'appdef.xml' was not found in the referenced package '{0}'", Path.GetFileName(FullPath))); } var appdefStream = new MemoryStream(); appdef.Extract(appdefStream); appdefStream.Position = 0; AppDef = XDocument.Load(appdefStream); PackageName = AppDef.Element("application").Element("name").Value; }
//<TimeOut>2.0</TimeOut> public TimeOutInitDetector(AppDef appDef, AppState appState, int processId, XElement xml) { this.appState = appState; this.processId = processId; this.appDef = appDef; try { var timeString = xml.Value; TimeOut = Double.Parse(timeString, CultureInfo.InvariantCulture); } catch { throw new InvalidAppInitDetectorArguments(Name, xml.ToString()); } appState.Initialized = false; // will be set to true as soon as the exit code condition is met InitialTicks = DateTime.UtcNow.Ticks; log.DebugFormat("TimeOutInitDetector: Waiting {0} sec, appid {1}, pid {2}", TimeOut, appDef.AppIdTuple, processId); }
public static IAppInitializedDetector create(AppDef appDef, AppState appState, int processId, XElement xml) { return new WindowPoppedUpInitDetector(appDef, appState, processId, xml); }
AppDef readAppElement( XElement e ) { AppDef a; // first load templates var templateName = X.getStringAttr(e, "Template"); if( templateName != "" ) { XElement te = (from t in doc.Element("Shared").Elements("AppTemplate") where (string) t.Attribute("Name") == templateName select t).First(); a = readAppElement( te ); } else { a = new AppDef(); } // read element content into memory, apply defaults var x = new { AppIdTuple = (string) e.Attribute("AppIdTuple"), ExeFullPath = (string) e.Attribute("ExeFullPath"), StartupDir = (string) e.Attribute("StartupDir"), CmdLineArgs = (string) e.Attribute("CmdLineArgs"), StartupOrder = (string) e.Attribute("StartupOrder"), RestartOnCrash = (string) e.Attribute("RestartOnCrash"), InitCondition = (string) e.Attribute("InitCondition"), SeparationInterval = (string) e.Attribute("SeparationInterval"), Dependecies = (string) e.Attribute("Dependencies"), KillTree = (string)e.Attribute("KillTree"), WindowStyle = (string)e.Attribute("WindowStyle"), WindowPos = e.Elements("WindowPos"), InitDetectors = e.Element("InitDetectors") != null ? e.Element("InitDetectors").Elements() : null, }; // then overwrite templated values with current content if( x.AppIdTuple != null ) a.AppIdTuple = new AppIdTuple( x.AppIdTuple ); if( x.ExeFullPath != null ) a.ExeFullPath = x.ExeFullPath; if( x.StartupDir != null ) a.StartupDir = x.StartupDir; if( x.CmdLineArgs != null ) a.CmdLineArgs = x.CmdLineArgs; if( x.StartupOrder != null ) a.StartupOrder = int.Parse( x.StartupOrder ); if( x.RestartOnCrash != null ) a.RestartOnCrash = (int.Parse( x.RestartOnCrash ) != 0); if( x.InitCondition != null ) a.InitializedCondition = x.InitCondition; if( x.SeparationInterval != null ) a.SeparationInterval = double.Parse(x.SeparationInterval, CultureInfo.InvariantCulture ); if (x.Dependecies != null) { var deps = new List<string>(); foreach( var d in x.Dependecies.Split(';')) { var stripped = d.Trim(); if( stripped != "" ) { deps.Add( d ); } } a.Dependencies = deps; } if (x.KillTree != null) a.KillTree = (int.Parse(x.KillTree) != 0); if (x.WindowStyle != null) { if (x.WindowStyle.ToLower() == "minimized") a.WindowStyle = ProcessWindowStyle.Minimized; else if (x.WindowStyle.ToLower() == "maximized") a.WindowStyle = ProcessWindowStyle.Maximized; else if (x.WindowStyle.ToLower() == "normal") a.WindowStyle = ProcessWindowStyle.Normal; else if (x.WindowStyle.ToLower() == "hidden") a.WindowStyle = ProcessWindowStyle.Hidden; } if( x.WindowPos != null ) { foreach( var elem in x.WindowPos ) { a.WindowPosXml.Add( elem.ToString() ); } } if( x.InitDetectors != null ) { foreach( var elem in x.InitDetectors ) { a.InitDetectors.Add( elem.ToString() ); } } return a; }
public void addLaunchedApp( AppDef appDef ) { appsLaunched.Add( appDef ); }
public void testDetectorFailsOnInvalidParams() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var d = new ExitCodeInitDetector(appDef, appState, 0, XElement.Parse("<timeout>abcd-not-a-double</timeout>")); }
public FakeLauncher( AppDef appDef, FakeLaunchFactory flf ) { this.appDef = appDef; this.flf = flf; }
public void testDetectorFailsOnInvalidParams() { AppDef appDef = new AppDef(); AppState appState = new AppState(); var d = new ExitCodeInitDetector(appDef, appState, 0, XElement.Parse("<timeout>abcd-not-a-double</timeout>")); }
/// <summary> /// Checks dependency conditions and launches apps in wawes /// Launches max. one app at a time, next one earliest after the previous one's separation interval. /// </summary> // FIXME: presunout do PlanRuntimeInfo void processPlan(double currentTime, ILaunchPlan plan) { // too frequent message filling up the log - commented out //log.Debug("processPlan"); if (plan == null) { return; } var rti = planRTInfo[plan.Name]; // if plan is stopped, don't start contained apps if (!rti.State.Running) { return; } // SPECIAL CASE for plans with all-volatile apps // Kill the plan as soon as all apps have terminated. // So the plan can be started again without being manually Killed first. // This is used for utility-plans launching some tools on the stations, // where the tools terminate automatically after they are done with their job. // Note: this won't kill any app as the Kill is initiated when no app is running any more. // (Usual non-volatile plans would not allow next start before prior KillPlan) { var currTime = DateTime.UtcNow; //bool allLaunched = true; //bool allNonVolatileRunning = true; bool anyNonVolatileApp = false; // is there at least one non-volatile? bool allAppsProcessed = true; bool anyStillRunning = false; foreach (var appDef in rti.Plan.getAppDefs()) { var apst = appsState[appDef.AppIdTuple]; bool isRemoteApp = appDef.AppIdTuple.MachineId != this.machineId; var statusInfoAge = currTime - apst.LastChange; bool offline = (isRemoteApp && statusInfoAge > TimeSpan.FromSeconds(3)); { } //if ( !offline & !(apst.PlanApplied && apst.Started && apst.Initialized)) //{ // allLaunched = false; //} if (!offline && !(apst.PlanApplied && (apst.Initialized || apst.StartFailed))) { allAppsProcessed = false; } if (!offline && apst.Running) { anyStillRunning = true; } if (!appDef.Volatile) { anyNonVolatileApp = true; //if (!apst.Running || offline) //{ // allNonVolatileRunning = false; //} } } if (allAppsProcessed && !anyNonVolatileApp && !anyStillRunning) // all apps volatile, all launched and none is running any longer { // Note: this won't kill any app as no apps are running any more. // It just make the plan startable again. KillPlan(plan.Name); } } // if no plan exists // or client re-connected and re-set the plan repo (then we loose the previous RTI) if (rti.launchDepChecker == null) { return; } // feed the sequencer with apps whose dependencies and constraints have already been satisfied if (rti.launchSequencer.IsEmpty()) { rti.launchSequencer.AddApps( rti.launchDepChecker.getAppsToLaunch() ); } // try to get an app to launch and launch it immediately AppDef appToLaunch = rti.launchSequencer.GetNext(currentTime); if (appToLaunch != null) { // remember that the app was already processed by the launch plan and should not be touched again // note: must be called before StartApp otherwise it would be enlessly re-tried by the launch plan if it throws exception during StartUp var la = localApps[appToLaunch.AppIdTuple]; var appState = appsState[la.AppDef.AppIdTuple]; appState.PlanApplied = true; LaunchApp(appToLaunch.AppIdTuple); } }
public void addLaunchedApp(AppDef appDef) { appsLaunched.Add(appDef); }
public ILauncher createLauncher(AppDef appDef, string rootForRelativePaths) { return(new FakeLauncher(appDef, this)); }
public FakeLauncher(AppDef appDef, FakeLaunchFactory flf) { this.appDef = appDef; this.flf = flf; }
public Launcher( AppDef appDef ) { this.appDef = appDef; }
static public IAppInitializedDetector create(AppDef appDef, AppState appState, int processId, XElement xml) { return(new TimeOutInitDetector(appDef, appState, processId, xml)); }
public ILauncher createLauncher( AppDef appDef ) { return new Launcher( appDef ); }
public ILauncher createLauncher(AppDef appDef) { return new FakeLauncher( appDef, this ); }