using System; using System.ComponentModel; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Text; using System.Windows.Media; using System.Windows.Input; using System.Threading.Tasks; using MarketData; using MarketData.Numerical; using MarketData.Utils; using MarketData.MarketDataModel; using MarketData.Generator; using MarketData.DataAccess; using TradeBlotter.DataAccess; using TradeBlotter.Command; using TradeBlotter.Model; using Microsoft.Research.DynamicDataDisplay.DataSources; using TradeBlotter.Cache; namespace TradeBlotter.ViewModels { public class DCFValuationViewModel : WorkspaceViewModel { private List symbols; private List watchLists; private String selectedWatchList; private String selectedSymbol; private String companyName; private ObservableCollection dcf = null; private bool busyIndicator = false; private DCFValuation dcfValuation = null; public DCFValuationViewModel() { base.DisplayName = "DCF Valuation"; watchLists = WatchListDA.GetWatchLists(); watchLists.Insert(0, Constants.CONST_ALL); selectedWatchList = watchLists.Find(x => x.Equals("Valuations")); symbols = WatchListDA.GetWatchList(selectedWatchList); selectedSymbol = null; PropertyChanged += OnDCFViewModelPropertyChanged; base.OnPropertyChanged("SelectedSymbol"); } // ******************************************************************************************** P E R S I S T E N C E ******************************************************************************************** public override bool CanPersist() { return true; } public override SaveParameters GetSaveParameters() { SaveParameters saveParams = new SaveParameters(); if (null == selectedSymbol) return null; saveParams.Add(new KeyValuePair("Type", GetType().Namespace + "." + GetType().Name)); saveParams.Add(new KeyValuePair("SelectedSymbol", selectedSymbol)); saveParams.Add(new KeyValuePair("SelectedWatchList", selectedWatchList)); return saveParams; } public override void SetSaveParameters(SaveParameters saveParameters) { try { if(saveParameters.ContainsKey("SelectedSymbol")) selectedSymbol=(from KeyValuePair item in saveParameters where item.Key.Equals("SelectedSymbol") select item).FirstOrDefault().Value; if(saveParameters.ContainsKey("SelectedWatchList")) selectedWatchList=(from KeyValuePair item in saveParameters where item.Key.Equals("SelectedWatchList") select item).FirstOrDefault().Value; Referer=saveParameters.Referer; base.OnPropertyChanged("SelectedWatchList"); base.OnPropertyChanged("SelectedSymbol"); } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString())); } } // ****************************************************************************************************************************************************** public bool BusyIndicator { get { return busyIndicator; } set { busyIndicator = value; base.OnPropertyChanged("BusyIndicator"); } } public ObservableCollection AllDCF { get { return dcf; } set { dcf = value; base.OnPropertyChanged("AllDCF"); } } private void OnDCFViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs) { if (eventArgs.PropertyName.Equals("SelectedSymbol")) { if(null==selectedSymbol)return; base.DisplayName = "Discounted Cashflow Valuation(" + selectedSymbol + ")"; base.OnPropertyChanged("DisplayName"); HandleSelectedSymbol(); } else if (eventArgs.PropertyName.Equals("SelectedWatchList")) { if(null==selectedWatchList)return; HandleSelectedWatchList(); } } private void HandleSelectedSymbol() { BusyIndicator = true; Task workerTask = Task.Factory.StartNew(() => { if (null != selectedSymbol) { dcf = null; companyName = PricingDA.GetNameForSymbol(selectedSymbol); dcfValuation = DCFGenerator.GenerateDCFValuation(selectedSymbol); if (null != dcfValuation.ReturnItems && 0 != dcfValuation.ReturnItems.Count) { dcf = new ObservableCollection(); for(int index=0;index { BusyIndicator = false; UpdateData(); UpdateDescriptions(); }); } private void UpdateData() { base.OnPropertyChanged("AllDCF"); base.OnPropertyChanged("Beta"); base.OnPropertyChanged("HistoricalMarketReturn"); base.OnPropertyChanged("RiskFreeRate"); base.OnPropertyChanged("MarketCap"); base.OnPropertyChanged("TotalDebt"); base.OnPropertyChanged("WACC"); base.OnPropertyChanged("ROIC"); base.OnPropertyChanged("CapitalBackground"); base.OnPropertyChanged("CostOfDebt"); base.OnPropertyChanged("CostOfEquity"); base.OnPropertyChanged("TaxRate"); base.OnPropertyChanged("TotalEquity"); base.OnPropertyChanged("TotalCapitalInvested"); base.OnPropertyChanged("InterestExpense"); base.OnPropertyChanged("OutstandingShares"); base.OnPropertyChanged("PresentValue"); base.OnPropertyChanged("EstimatedStockPrice"); base.OnPropertyChanged("MOS"); base.OnPropertyChanged("MOSBackground"); base.OnPropertyChanged("MOS80"); base.OnPropertyChanged("MOS80Background"); base.OnPropertyChanged("IntrinsicValue"); base.OnPropertyChanged("RGVIntrinsic"); base.OnPropertyChanged("IntrinsicValueRevised"); base.OnPropertyChanged("RGVIntrinsicValueRevised"); base.OnPropertyChanged("CurrentPrice"); base.OnPropertyChanged("PriceDate"); base.OnPropertyChanged("FreeCashflowGrowth"); base.OnPropertyChanged("Message"); base.OnPropertyChanged("Title"); } private void UpdateDescriptions() { base.OnPropertyChanged("BetaDescription"); base.OnPropertyChanged("InterestExpenseDescription"); base.OnPropertyChanged("CostOfEquityDescription"); base.OnPropertyChanged("CostOfDebtDescription"); base.OnPropertyChanged("ROICDescription"); base.OnPropertyChanged("WACCDescription"); base.OnPropertyChanged("TotalCapitalInvestedDescription"); base.OnPropertyChanged("TotalLongAndShortTermDebtDescription"); base.OnPropertyChanged("TotalEquityDescription"); base.OnPropertyChanged("RiskFreeRateDescription"); base.OnPropertyChanged("HistoricalMarketReturnDescription"); base.OnPropertyChanged("OutstandingSharesDescription"); base.OnPropertyChanged("MOSDescription"); base.OnPropertyChanged("MOS80Description"); base.OnPropertyChanged("SumOfDiscountedCashflowsDescription"); base.OnPropertyChanged("EstimatedStockPriceDescription"); base.OnPropertyChanged("LatestPriceDescription"); base.OnPropertyChanged("PriceDateDescription"); base.OnPropertyChanged("IntrinsicValueDescription"); base.OnPropertyChanged("IntrinsicValueRevisedDescription"); base.OnPropertyChanged("RGVIntrinsicRevDescription"); base.OnPropertyChanged("FreeCashflowGrowthDescription"); } public void OnErrorItemHandler(String symbol, String message) { } private void HandleSelectedWatchList() { // if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = PricingDA.GetSymbols(); if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = SymbolCache.GetInstance().GetSymbols(); else { symbols = WatchListDA.GetWatchList(selectedWatchList); } base.OnPropertyChanged("Symbols"); } // ************************************************************************************************************************************************************************ // ********************************************************************************** C O L O R S C H E M E ************************************************************** // ************************************************************************************************************************************************************************ public Brush CapitalBackground { get { if (null == dcfValuation || !dcfValuation.Success) return null; if (dcfValuation.Enhancements.ROIC > dcfValuation.WACC) return new SolidColorBrush(Colors.LightGreen); return new SolidColorBrush(Colors.Red); } } public Brush MOSBackground { get { if (null == dcfValuation || !dcfValuation.Success || null == dcfValuation.CurrentPrice) return null; if (dcfValuation.CurrentPrice.Close > dcfValuation.StockPriceValuation) return new SolidColorBrush(Colors.Red); return new SolidColorBrush(Colors.LightGreen); } } public Brush MOS80Background { get { if (null == dcfValuation || !dcfValuation.Success || null == dcfValuation.CurrentPrice) return null; if (dcfValuation.CurrentPrice.Close > dcfValuation.StockPriceValuation) return new SolidColorBrush(Colors.Red); return new SolidColorBrush(Colors.LightGreen); } } // ************************************************************************************************************************************************************************ public override String Title { get { if (null != companyName && null != selectedSymbol) return "Discounted Cashflow Valuation - (" + selectedSymbol + ") " + companyName; return "Discounted Cashflow Valuation"; } } public String Beta { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Beta)? Constants.CONST_DASHES : Utility.FormatNumber(dcfValuation.Beta,2); } } public String HistoricalMarketReturn { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.MarketReturn) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.MarketReturn); } } public String RiskFreeRate { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.RiskFreeRate) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.RiskFreeRate); } } public String MarketCap { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.MarketValueOfEquity) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.MarketValueOfEquity); } } public String TotalDebt { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.TotalDebt) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.TotalDebt); } } public String WACC { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.WACC) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.WACC); } } public String ROIC { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Enhancements.ROIC) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.Enhancements.ROIC); } } public String CostOfDebt { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.CostOfDebt) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.CostOfDebt); } } public String CostOfEquity { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.CostOfEquity) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.CostOfEquity); } } public String TaxRate { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.CorporateTaxRate) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.CorporateTaxRate); } } public String TotalEquity { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.MarketValueOfEquity) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.MarketValueOfEquity); } } public String TotalCapitalInvested { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.TotalCapitalInvested) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.TotalCapitalInvested); } } public String InterestExpense { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.InterestExpense) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.InterestExpense); } } public String OutstandingShares { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.OutstandingShares) ? Constants.CONST_DASHES : Utility.FormatNumber(dcfValuation.OutstandingShares, 0, true); } } public String PresentValue { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.PresentValue) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.PresentValue); } } public String EstimatedStockPrice { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.StockPriceValuation) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.StockPriceValuation); } } public String CurrentPrice { get { return dcfValuation == null || !dcfValuation.Success || null == dcfValuation.CurrentPrice || double.NaN.Equals(dcfValuation.CurrentPrice.Close) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.CurrentPrice.Close); } } public String PriceDate { get { return dcfValuation == null || !dcfValuation.Success || null == dcfValuation.CurrentPrice ? Constants.CONST_DASHES : Utility.DateTimeToStringMMHDDHYYYY(dcfValuation.CurrentPrice.Date); } } public String FreeCashflowGrowth { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.FreeCashflowGrowth) ? Constants.CONST_DASHES : Utility.FormatPercent(dcfValuation.FreeCashflowGrowth); } } public String MOS { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Enhancements.MOS) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.Enhancements.MOS); } } public String MOS80 { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Enhancements.MOS80) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.Enhancements.MOS80); } } public String IntrinsicValue { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Enhancements.IntrinsicValue) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.Enhancements.IntrinsicValue); } } public String RGVIntrinsic { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Enhancements.RGVIntrinsic) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.Enhancements.RGVIntrinsic); } } public String IntrinsicValueRevised { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Enhancements.IntrinsicValueRevised) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.Enhancements.IntrinsicValueRevised); } } public String RGVIntrinsicValueRevised { get { return dcfValuation == null || !dcfValuation.Success || double.NaN.Equals(dcfValuation.Enhancements.RGVIntrinsicRevised) ? Constants.CONST_DASHES : Utility.FormatCurrency(dcfValuation.Enhancements.RGVIntrinsicRevised); } } public String Message { get { return dcfValuation == null ? Constants.CONST_DASHES : dcfValuation.Message; } } public List Symbols { get { return symbols; } } public String SelectedSymbol { get { return selectedSymbol; } set { if (value == selectedSymbol || String.IsNullOrEmpty(value)) return; selectedSymbol = value; base.OnPropertyChanged("SelectedSymbol"); } } public List WatchListNames { get { return watchLists; } set { ;} } public String SelectedWatchList { get { return selectedWatchList; } set { selectedWatchList = value; base.OnPropertyChanged("SelectedWatchList"); } } // ************************************************************************************************************************************************************************************************************************************************ // ************************************************************************************************ T O O L T I P C A L L O U T S ************************************************************************************************************** // ************************************************************************************************************************************************************************************************************************************************ public String HistoricalMarketReturnDescription { get { try { StringBuilder sb=new StringBuilder(); if(dcfValuation.UseMarketReturn)sb.Append("Using a calculated market return of ").Append(Utility.FormatPercent(dcfValuation.MarketReturn,2)); else sb.Append("Using a constant market return of ").Append(Utility.FormatPercent(dcfValuation.MarketReturn,2)); return sb.ToString(); } catch(Exception) { return Constants.NA; } } } public String BetaDescription { get { try { StringBuilder sb=new StringBuilder(); sb.Append("Beta is a measure of a stock's volatility in relation to the overall market. By definition, the market, such as the S&P 500 Index, has a beta of 1.0, and individual stocks are ranked according to how").Append("\n"); sb.Append("much they deviate from the market. A stock that swings more than the market has a beta above 1.0. If a stock moves less than the market, the stock's beta is less than 1.0. ").Append("\n"); sb.Append("High-beta stocks are supposed to be riskier but provide higher return potential; low-beta stocks pose less risk but also lower returns. ").Append("\n"); sb.Append("Beta = 36 month internally calculated beta.").Append("\n"); sb.Append("Beta = Covariance(Ra,Rm)/Variance(Ra). Where Rm = Return of the market (SPY), Ra = Return of the asset.").Append("\n"); sb.Append(dcfValuation.Symbol).Append(" has a Beta of ").Append(Utility.FormatNumber(dcfValuation.Beta,2)).Append(" which is ").Append(dcfValuation.Beta>1?"more volatile ":"less volatile ").Append("than the market.").Append("\n"); sb.Append(dcfValuation.Symbol).Append(" offers ").Append(dcfValuation.Beta>1?"more risk but more return potential ":"less risk but less return potential ").Append("than the market.").Append("\n"); return sb.ToString(); } catch(Exception) { return Constants.NA; } } } public String InterestExpenseDescription { get { return "Interest Expense (Annual): This is sourced from Historical(M*) as 'InterestExpense' if available otherwise from the IncomeStatement as 'InterestExpense'"; } } public String CostOfEquityDescription { get { try { StringBuilder sb=new StringBuilder(); sb.Append("Cost of equity is the return that a company requires for an investment or project, or the return that an individual requires for an equity investment.").Append("\n"); sb.Append("Cost of Equity: Using CAPM cost of equity is calculated as rE = RFR + Beta * (Rm - RFR). Where RFR=Risk Free Rate, Beta=Market Beta, Rm=Annual Return.").Append("\n"); sb.Append("rE = ").Append(Utility.FormatNumber(dcfValuation.RiskFreeRate,2)).Append(" + "); sb.Append(Utility.FormatNumber(dcfValuation.Beta,2)).Append(" * ").Append("("); sb.Append(Utility.FormatNumber(dcfValuation.MarketReturn)).Append(" - ").Append(Utility.FormatNumber(dcfValuation.RiskFreeRate,2)).Append(")"); if(dcfValuation.UseMarketReturn)sb.Append("Using a calculated market return of ").Append(Utility.FormatNumber(dcfValuation.MarketReturn,2)); else sb.Append("Using a constant market return of ").Append(Utility.FormatNumber(dcfValuation.MarketReturn,2)); return sb.ToString(); } catch(Exception) { return Constants.NA; } } } public String CostOfDebtDescription { get { try { StringBuilder sb=new StringBuilder(); sb.Append("Cost of debt is the effective interest rate that a company pays on its debts, such as bonds and loans.").Append("\n"); sb.Append("Cost of Debt rD = ( Ei / D) * (1 - Tc).").Append("Where Ei = Interest Expense, D = Total Debt, Tc = Tax Rate.").Append("\n"); sb.Append("rD = ").Append(Utility.FormatNumber(dcfValuation.InterestExpense,2,true)).Append(" / ").Append(Utility.FormatNumber(dcfValuation.TotalDebt,2,true)).Append(")"); sb.Append(" * ").Append("(").Append(Utility.FormatNumber(1,2)).Append(" - ").Append(Utility.FormatNumber(dcfValuation.CorporateTaxRate,2)).Append(")"); return sb.ToString(); } catch(Exception) { return Constants.NA; } } } public String RiskFreeRateDescription { get { return "Current yield on 90 day (3M) Treasury. This can be verified by going to the \"Treasury Yield Curve\" tab and looking at the current 3M value."; } } public String ROICDescription { get { StringBuilder sb=new StringBuilder(); sb.Append("Return on Invested Capital. Sourced from historical time series").Append("\n"); sb.Append(@"Return on Invested Capital (ROIC) is a return ratio that expresses recurring operating profits as a percentage of the company's net operational assets ").Append("\n"); sb.Append("The profit figure used is earnings before interest and taxes or EBIT and is unaffected by capital structure.").Append("\n"); return sb.ToString(); } } public String WACCDescription { get { try { StringBuilder sb=new StringBuilder(); sb.Append("Weighted average cost of capital (WACC) represents a firm’s average after-tax cost of capital from all sources, including common stock, preferred stock, bonds, and other forms of debt.").Append("\n"); sb.Append("WACC is the average rate that a company expects to pay to finance its assets.").Append("\n"); sb.Append("WACC is a common way to determine required rate of return (RRR) because it expresses, in a single number, the return that both bondholders and shareholders demand to provide the company with capital").Append("\n"); sb.Append("WACC = rE * (E / V) + rD * (1 - Tc) * (D / V) .").Append("\n"); sb.Append("Where rE = Cost of Equity, E = Total Equity, V = Total Capital Invested, rD = Cost of Debt, Tc = Tax Rate, D = Total Debt").Append("\n"); sb.Append(Utility.FormatNumber(dcfValuation.CostOfEquity,2,true)).Append(" * " ).Append("(").Append(Utility.FormatNumber(dcfValuation.MarketValueOfEquity,2,true)).Append(" / ").Append(Utility.FormatNumber(dcfValuation.TotalCapitalInvested,2,true)).Append(")"); sb.Append(" + "); sb.Append("("); sb.Append(Utility.FormatNumber(dcfValuation.CostOfDebt,2,true)).Append(" * ").Append("(").Append(Utility.FormatNumber(dcfValuation.MarketValueOfDebt,2,true)).Append(" / ").Append(Utility.FormatNumber(dcfValuation.TotalCapitalInvested,2,true)).Append(")"); sb.Append(" * ").Append("(").Append(Utility.FormatNumber(1,2)).Append(" - ").Append(Utility.FormatNumber(dcfValuation.CorporateTaxRate,2)).Append(")"); sb.Append(")"); sb.Append("\n"); return sb.ToString(); } catch(Exception) { return Constants.NA; } } } public String TotalCapitalInvestedDescription { get { StringBuilder sb=new StringBuilder(); sb.Append("Total Capital Invested : "); sb.Append("V = MV(D) + MV(E) Where MV(D) = Market value of debt, MV(E) = Market value of equity.").Append("\n"); sb.Append("Market value of debt is sourced from Fundamentals").Append("\n"); sb.Append("Market value of equity is sourced from Fundamentals").Append("\n"); return sb.ToString(); } } public String EstimatedStockPriceDescription { get { StringBuilder sb=new StringBuilder(); sb.Append("Estimated Stock Price : This is the sum of the discounted cashflows minus debt; then divided by outstanding shares.").Append("\n"); sb.Append("Estimated Stock Price = (Present Value - Debt) / Outstanding Shares.").Append("\n"); sb.Append("(").Append(Utility.FormatNumber(dcfValuation.PresentValue,2,true)).Append(" - ").Append(Utility.FormatNumber(dcfValuation.TotalDebt,2,true)).Append(")").Append(" / ").Append(Utility.FormatNumber(dcfValuation.OutstandingShares,2,true)).Append("\n"); sb.Append("Please refer to Debt and Oustanding Shares to see the source of those values").Append("\n"); return sb.ToString(); } } public String TotalLongAndShortTermDebtDescription { get{return "Total Long and Short Term Debt : This value if sourced from Fundamentals as TotalDebt";} } public String TotalEquityDescription { get{return "Total Equity : This value if sourced from Fundamentals as MarketCap";} } public String OutstandingSharesDescription { get{return "Outstanding Shares : This is sourced from Fundamentals as SharesOutstanding";} } public String MOSDescription { get{return "Est. Stock Price *.5";} } public String MOS80Description { get{return "Est. Stock Price *.8";} } public String SumOfDiscountedCashflowsDescription { get{return "Sum of discounted cashflows. This is also known as the PresentValue.";} } public String LatestPriceDescription { get{return "Latest closing price in database.";} } public String PriceDateDescription { get{return "Date of latest closing price in database.";} } public String IntrinsicValueDescription { get{return "Benjamin Graham : EPS*(8.5+(2*EPSGrowth))";} } public String IntrinsicValueRevisedDescription { get{return "Benjamin Graham : (EPS*(8.5+(2*EPSGrowth))+4.4) / Yield on 20-year AAA bonds.";} } public String RGVIntrinsicRevDescription { get{return "Intrinsic Value Rev./ Last closing price.";} } public String FreeCashflowGrowthDescription { get{return "Mean of freecashflow returns.";} } } }