public List <QNode> nodes() { var bySystem = new LazyDictionary <string, List <LiveSystem> > (system => new List <LiveSystem>()); each(systems, liveSystem => bySystem.get(liveSystem.siv().system()).Add(liveSystem)); var result = list(convert(bySystem.keys(), system => { var liveSystems = bySystem.get(system); var systemNode = new QNode(system, liveSystems.Count, 0); each(liveSystems, liveSystem => { var liveSystemNode = systemNode.add(new LiveSystemNode(liveSystem, 1, 0)); var liveMarkets = list <MsivPv>(liveSystem.liveMarkets()); each(liveMarkets, liveMarket => { try { var symbol = new Symbol(liveMarket.market()); var liveMarketNode = new LiveMarketNode(symbol, 1, 0); liveSystemNode.add(liveMarketNode); var topic = new Topic(liveSystem.topicName(OrderTable.prefix, symbol.name + "." + SystemHeartbeat.SUFFIX)); topic.subscribeIfNeeded(); updateModelNodes += () => updateNode(topic, liveMarket, liveMarketNode); symbol.subscribe(bar => recordMarketDataTickReceived(liveMarket, bar.time)); topic.subscribe(fields => { var tickTime = fields.time("lastTickProcessed"); ticks.get(liveMarket).systemProcessed(date(tickTime)); }); } catch (Exception ex) { LogC.err("exception caught subscribing to tick data for " + liveMarket + ", " + system, ex); gui.alertUser("exception caught susbcribing to data for " + liveMarket + ", " + system + ".\nSkipping... see log for details."); } }); updateModelNodes += () => updateNode(liveSystem, liveSystemNode); }); updateModelNodes += () => updateNode(systemNode); return(systemNode); })); timerManager().everyMillis(1000, updateModelNodes, out timer); LiveLauncher.subscribeHeartbeat(gui.launcherAvailable); LogC.ignore(timer); return(result); }