private bool ProcessReset(Message message)
        {
            lock (_sync)
            {
                _historicalRequests.Clear();
                _subscriptionsById.Clear();
                _replaceId.Clear();
                _allSecIdChilds.Clear();
                _reMapSubscriptions.Clear();
            }

            return(base.OnSendInMessage(message));
        }
 private void ClearState()
 {
     lock (_sync)
     {
         _subscriptionsByKey.Clear();
         _subscriptionsById.Clear();
     }
 }
Exemplo n.º 3
0
        /// <summary>
        /// Release resources.
        /// </summary>
        protected override void DisposeManaged()
        {
            _writers.Values.ForEach(w => w.Dispose());

            _fileNames.Clear();
            _writers.Clear();

            base.DisposeManaged();
        }
Exemplo n.º 4
0
        private void ProcessReset(Message message)
        {
            lock (_sync)
            {
                _historicalRequests.Clear();
                _subscriptionsByKey.Clear();
                _subscriptionsById.Clear();
            }

            base.OnSendInMessage(message);
        }
Exemplo n.º 5
0
        private static Pair[] _TempBufferPairs_ToArrayAndClear()
        {
            var pairs_new = new Pair[_TempBufferPairs.Count];
            var it        = _TempBufferPairs.GetEnumerator();

            for (var i = 0; it.MoveNext(); i++)
            {
                pairs_new[i] = it.Current;
            }
            _TempBufferPairs.Clear();
            return(pairs_new);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Process <see cref="MessageAdapterWrapper.InnerAdapter"/> output message.
        /// </summary>
        /// <param name="message">The message.</param>
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Connect:
            {
                var nativeIds = Storage.Get(InnerAdapter.StorageName);

                lock (_syncRoot)
                {
                    foreach (var tuple in nativeIds)
                    {
                        var securityId = tuple.Item1;
                        var nativeId   = tuple.Item2;

                        _securityIds[nativeId] = securityId;
                    }
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.Reset:
            {
                lock (_syncRoot)
                {
                    _securityIds.Clear();
                    _suspendedOutMessages.Clear();
                    _suspendedInMessages.Clear();
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.Security:
            {
                var secMsg     = (SecurityMessage)message;
                var securityId = secMsg.SecurityId;

                var nativeSecurityId = securityId.Native;
                var securityCode     = securityId.SecurityCode;
                var boardCode        = securityId.BoardCode;

                if (securityCode.IsEmpty())
                {
                    throw new InvalidOperationException();
                }

                if (securityId.SecurityType == null)
                {
                    securityId.SecurityType = secMsg.SecurityType;
                }

                // external code shouldn't receive native ids
                securityId.Native = null;

                if (!boardCode.IsEmpty())
                {
                    if (nativeSecurityId != null)
                    {
                        var storageName = InnerAdapter.StorageName;

                        if (!Storage.TryAdd(storageName, securityId, nativeSecurityId, InnerAdapter.IsNativeIdentifiersPersistable))
                        {
                            var prevId = Storage.TryGetByNativeId(storageName, nativeSecurityId);

                            if (prevId != null)
                            {
                                if (securityId != prevId.Value)
                                {
                                    throw new InvalidOperationException(LocalizedStrings.Str687Params.Put(securityId, prevId.Value, nativeSecurityId));
                                }
                            }
                            else
                            {
                                throw new InvalidOperationException(LocalizedStrings.Str687Params.Put(Storage.TryGetBySecurityId(storageName, securityId), nativeSecurityId, securityId));
                            }
                        }

                        lock (_syncRoot)
                            _securityIds[nativeSecurityId] = securityId;
                    }
                }
                else
                {
                    // TODO
                }

                base.OnInnerAdapterNewOutMessage(message);

                ProcessSuspendedSecurityMessages(secMsg.SecurityId);

                break;
            }

            //case MessageTypes.Position:
            //{
            //	var positionMsg = (PositionMessage)message;
            //	ProcessMessage(positionMsg.SecurityId, positionMsg, null);
            //	break;
            //}

            case MessageTypes.PositionChange:
            {
                var positionMsg = (PositionChangeMessage)message;

                ProcessMessage(positionMsg.SecurityId, positionMsg, (prev, curr) =>
                    {
                        foreach (var pair in prev.Changes)
                        {
                            curr.Changes.TryAdd(pair.Key, pair.Value);
                        }

                        return(curr);
                    });
                break;
            }

            case MessageTypes.Execution:
            {
                var execMsg = (ExecutionMessage)message;
                ProcessMessage(execMsg.SecurityId, execMsg, null);
                break;
            }

            case MessageTypes.Level1Change:
            {
                var level1Msg = (Level1ChangeMessage)message;

                ProcessMessage(level1Msg.SecurityId, level1Msg, (prev, curr) =>
                    {
                        foreach (var pair in prev.Changes)
                        {
                            curr.Changes.TryAdd(pair.Key, pair.Value);
                        }

                        return(curr);
                    });
                break;
            }

            case MessageTypes.QuoteChange:
            {
                var quoteChangeMsg = (QuoteChangeMessage)message;
                ProcessMessage(quoteChangeMsg.SecurityId, quoteChangeMsg, (prev, curr) => curr);
                break;
            }

            case MessageTypes.CandleTimeFrame:
            case MessageTypes.CandleRange:
            case MessageTypes.CandlePnF:
            case MessageTypes.CandleRenko:
            case MessageTypes.CandleTick:
            case MessageTypes.CandleVolume:
            {
                var candleMsg = (CandleMessage)message;
                ProcessMessage(candleMsg.SecurityId, candleMsg, null);
                break;
            }

            case MessageTypes.News:
            {
                var newsMsg = (NewsMessage)message;

                if (newsMsg.SecurityId != null)
                {
                    ProcessMessage(newsMsg.SecurityId.Value, newsMsg, null);
                }
                else
                {
                    base.OnInnerAdapterNewOutMessage(message);
                }

                break;
            }

            default:
                base.OnInnerAdapterNewOutMessage(message);
                break;
            }
        }
Exemplo n.º 7
0
 protected override void OnCleared()
 {
     _transactionIds.Clear();
     base.OnCleared();
 }
Exemplo n.º 8
0
        /// <inheritdoc />
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            if (message.IsBack)
            {
                base.OnInnerAdapterNewOutMessage(message);
                return;
            }

            switch (message.Type)
            {
            case MessageTypes.Connect:
            {
                var mappings = Storage.Get(StorageName);

                lock (_syncRoot)
                {
                    foreach (var mapping in mappings)
                    {
                        _securityIds.Add(mapping.StockSharpId, mapping.AdapterId);
                    }
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.Reset:
            {
                lock (_syncRoot)
                {
                    _securityIds.Clear();
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.Security:
            {
                var secMsg = (SecurityMessage)message;

                var adapterId = secMsg.SecurityId.SetNativeId(null);

                if (adapterId.IsDefault())
                {
                    throw new InvalidOperationException(secMsg.ToString());
                }

                lock (_syncRoot)
                {
                    if (_securityIds.TryGetValue(adapterId, out var stockSharpId))
                    {
                        secMsg.SecurityId = stockSharpId;
                    }
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.News:
            {
                var newsMsg = (NewsMessage)message;

                if (newsMsg.SecurityId != null)
                {
                    ProcessMessage(newsMsg.SecurityId.Value, newsMsg);
                }
                else
                {
                    base.OnInnerAdapterNewOutMessage(message);
                }

                break;
            }

            default:
            {
                if (message is ISecurityIdMessage secIdMsg)
                {
                    ProcessMessage(secIdMsg.SecurityId, message);
                }
                else
                {
                    base.OnInnerAdapterNewOutMessage(message);
                }

                break;
            }
            }
        }
        /// <inheritdoc />
        protected override bool OnSendInMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_syncRoot)
                {
                    _securityIds.Clear();
                    _suspendedOutMessages.Clear();
                    _suspendedInMessages.Clear();
                    _skipTransactions.Clear();
                }

                break;
            }

            case MessageTypes.OrderRegister:
            case MessageTypes.OrderReplace:
            case MessageTypes.OrderCancel:
            case MessageTypes.OrderGroupCancel:
            case MessageTypes.MarketData:
            {
                var secMsg = (SecurityMessage)message;

                if (secMsg.SecurityId == default)
                {
                    break;
                }

                var securityId = secMsg.SecurityId;

                var native = GetNativeId(secMsg, securityId);

                if (native == null)
                {
                    if (securityId.Native != null)
                    {
                        lock (_syncRoot)
                            _skipTransactions.Add(((ITransactionIdMessage)secMsg).TransactionId);

                        break;
                    }

                    return(true);
                }

                securityId.Native = native;
                message.ReplaceSecurityId(securityId);

                break;
            }

            case MessageTypes.OrderPairReplace:
            {
                var pairMsg = (OrderPairReplaceMessage)message;

                var securityId1 = pairMsg.Message1.SecurityId;
                var securityId2 = pairMsg.Message2.SecurityId;

                if (securityId1.Native != null && securityId2.Native != null)
                {
                    break;
                }

                var nativeId1 = GetNativeId(pairMsg, securityId1);

                if (nativeId1 == null)
                {
                    return(true);
                }

                var nativeId2 = GetNativeId(pairMsg, securityId2);

                if (nativeId2 == null)
                {
                    return(true);
                }

                securityId1.Native = nativeId1;
                pairMsg.Message1.ReplaceSecurityId(securityId1);

                securityId2.Native = nativeId2;
                pairMsg.Message2.ReplaceSecurityId(securityId2);
                break;
            }

            case ExtendedMessageTypes.ProcessSuspendedSecurityMessages:
                ProcessSuspendedSecurityMessages(((ProcessSuspendedSecurityMessage)message).SecurityId);
                break;
            }

            return(base.OnSendInMessage(message));
        }
Exemplo n.º 10
0
        /// <summary>
        /// Process <see cref="MessageAdapterWrapper.InnerAdapter"/> output message.
        /// </summary>
        /// <param name="message">The message.</param>
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_syncRoot)
                {
                    _securityIds.Clear();
                    _suspendedMessages.Clear();
                    _nativeIds.Clear();
                }

                break;
            }

            case MessageTypes.Security:
            {
                var secMsg     = (SecurityMessage)message;
                var securityId = secMsg.SecurityId;

                var nativeSecurityId = securityId.Native;
                var securityCode     = securityId.SecurityCode;
                var boardCode        = securityId.BoardCode;

                if (securityCode.IsEmpty())
                {
                    throw new InvalidOperationException();
                }

                if (securityId.SecurityType == null)
                {
                    securityId.SecurityType = secMsg.SecurityType;
                }

                var isNativeIdNull = nativeSecurityId == null;

                if (!boardCode.IsEmpty())
                {
                    lock (_syncRoot)
                    {
                        _securityIds[securityId] = securityId;

                        var temp = securityId;
                        // GetHashCode shouldn't calc based on native id
                        temp.Native = null;

                        if (!isNativeIdNull && !_nativeIds.TryAdd(temp, nativeSecurityId))
                        {
                            SecurityId prevId;

                            if (_nativeIds.TryGetKey(nativeSecurityId, out prevId))
                            {
                                if (temp != prevId)
                                {
                                    throw new InvalidOperationException(LocalizedStrings.Str687Params.Put(temp, prevId, nativeSecurityId));
                                }
                            }
                            else
                            {
                                throw new InvalidOperationException(LocalizedStrings.Str687Params.Put(nativeSecurityId, _nativeIds[temp], temp));
                            }
                        }
                    }
                }
                else
                {
                    // TODO
                }

                base.OnInnerAdapterNewOutMessage(message);

                ProcessSuspendedSecurityMessages(securityId);

                break;
            }

            case MessageTypes.Position:
            {
                var positionMsg = (PositionMessage)message;
                ProcessMessage(positionMsg.SecurityId, positionMsg, null);
                break;
            }

            case MessageTypes.PositionChange:
            {
                var positionMsg = (PositionChangeMessage)message;

                ProcessMessage(positionMsg.SecurityId, positionMsg, (prev, curr) =>
                    {
                        foreach (var pair in prev.Changes)
                        {
                            curr.Changes.TryAdd(pair.Key, pair.Value);
                        }

                        return(curr);
                    });
                break;
            }

            case MessageTypes.Execution:
            {
                var execMsg = (ExecutionMessage)message;
                ProcessMessage(execMsg.SecurityId, execMsg, null);
                break;
            }

            case MessageTypes.Level1Change:
            {
                var level1Msg = (Level1ChangeMessage)message;

                ProcessMessage(level1Msg.SecurityId, level1Msg, (prev, curr) =>
                    {
                        foreach (var pair in prev.Changes)
                        {
                            curr.Changes.TryAdd(pair.Key, pair.Value);
                        }

                        return(curr);
                    });
                break;
            }

            case MessageTypes.QuoteChange:
            {
                var quoteChangeMsg = (QuoteChangeMessage)message;
                ProcessMessage(quoteChangeMsg.SecurityId, quoteChangeMsg, (prev, curr) => curr);
                break;
            }

            case MessageTypes.News:
            {
                var newsMsg = (NewsMessage)message;

                if (newsMsg.SecurityId != null)
                {
                    ProcessMessage(newsMsg.SecurityId.Value, newsMsg, null);
                }

                break;
            }

            default:
                base.OnInnerAdapterNewOutMessage(message);
                break;
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Process <see cref="MessageAdapterWrapper.InnerAdapter"/> output message.
        /// </summary>
        /// <param name="message">The message.</param>
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Connect:
            {
                var mappings = Storage.Get(StorageName);

                lock (_syncRoot)
                {
                    foreach (var mapping in mappings)
                    {
                        _securityIds.Add(mapping.StockSharpId, mapping.AdapterId);
                    }
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.Reset:
            {
                lock (_syncRoot)
                {
                    _securityIds.Clear();
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.Security:
            {
                var secMsg = (SecurityMessage)message;

                var securityCode = secMsg.SecurityId.SecurityCode;
                var boardCode    = secMsg.SecurityId.BoardCode;

                if (securityCode.IsEmpty() || boardCode.IsEmpty())
                {
                    throw new InvalidOperationException();
                }

                var adapterId = new SecurityId
                {
                    SecurityCode = securityCode,
                    BoardCode    = boardCode
                };

                SecurityId?stockSharpId;

                lock (_syncRoot)
                    stockSharpId = _securityIds.TryGetValue2(adapterId);

                if (stockSharpId != null)
                {
                    secMsg.SecurityId = stockSharpId.Value;
                }

                base.OnInnerAdapterNewOutMessage(message);
                break;
            }

            case MessageTypes.PositionChange:
            {
                var positionMsg = (PositionChangeMessage)message;

                ProcessMessage(positionMsg.SecurityId, positionMsg);
                break;
            }

            case MessageTypes.Execution:
            {
                var execMsg = (ExecutionMessage)message;
                ProcessMessage(execMsg.SecurityId, execMsg);
                break;
            }

            case MessageTypes.Level1Change:
            {
                var level1Msg = (Level1ChangeMessage)message;

                ProcessMessage(level1Msg.SecurityId, level1Msg);
                break;
            }

            case MessageTypes.QuoteChange:
            {
                var quoteChangeMsg = (QuoteChangeMessage)message;
                ProcessMessage(quoteChangeMsg.SecurityId, quoteChangeMsg);
                break;
            }

            case MessageTypes.CandleTimeFrame:
            case MessageTypes.CandleRange:
            case MessageTypes.CandlePnF:
            case MessageTypes.CandleRenko:
            case MessageTypes.CandleTick:
            case MessageTypes.CandleVolume:
            {
                var candleMsg = (CandleMessage)message;
                ProcessMessage(candleMsg.SecurityId, candleMsg);
                break;
            }

            case MessageTypes.News:
            {
                var newsMsg = (NewsMessage)message;

                if (newsMsg.SecurityId != null)
                {
                    ProcessMessage(newsMsg.SecurityId.Value, newsMsg);
                }
                else
                {
                    base.OnInnerAdapterNewOutMessage(message);
                }

                break;
            }

            default:
                base.OnInnerAdapterNewOutMessage(message);
                break;
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// Записать сообщения.
        /// </summary>
        /// <param name="messages">Отладочные сообщения.</param>
        protected override void OnWriteMessages(IEnumerable <LogMessage> messages)
        {
            // pyh: эмуляция года данных происходит за 5 секунд. На выходе 365 файлов лога? Бред.
            //var date = SeparateByDates != SeparateByDateModes.None ? message.Time.Date : default(DateTime);
            var date = SeparateByDates != SeparateByDateModes.None ? DateTime.Today : default(DateTime);

            string       prevFileName = null;
            StreamWriter prevWriter   = null;

            var isDisposing = false;

            foreach (var group in messages.GroupBy(m =>
            {
                if (isDisposing || m.IsDispose)
                {
                    isDisposing = true;
                    return(null);
                }

                var fileName = FileName ?? GetSourceName(m.Source);

                if (prevFileName == fileName)
                {
                    return(prevWriter);
                }

                var key = Tuple.Create(fileName, date);

                var writer = _writers.TryGetValue(key);

                if (writer == null)
                {
                    if (isDisposing)
                    {
                        return(null);
                    }

                    writer = OnCreateWriter(GetFileName(fileName, date));
                    _writers.Add(key, writer);
                }

                prevFileName = fileName;
                prevWriter = writer;
                return(writer);
            }).AsParallel())
            {
                if (isDisposing)
                {
                    _writers.Values.ForEach(w => w.Dispose());
                    _writers.Clear();
                    return;
                }

                var writer = group.Key;

                try
                {
                    foreach (var message in group)
                    {
                        WriteMessage(writer, message);

                        if (MaxLength <= 0 || writer.BaseStream.Position < MaxLength)
                        {
                            continue;
                        }

                        var fileName = _fileNames[writer];
                        _fileNames.Remove(writer);

                        var key = _writers[writer];
                        writer.Dispose();

                        var maxIndex = 0;

                        while (File.Exists(GetRollingFileName(fileName, maxIndex + 1)))
                        {
                            maxIndex++;
                        }

                        for (var i = maxIndex; i > 0; i--)
                        {
                            File.Move(GetRollingFileName(fileName, i), GetRollingFileName(fileName, i + 1));
                        }

                        File.Move(fileName, GetRollingFileName(fileName, 1));

                        if (MaxCount > 0)
                        {
                            maxIndex++;

                            for (var i = MaxCount; i <= maxIndex; i++)
                            {
                                File.Delete(GetRollingFileName(fileName, i));
                            }
                        }

                        writer        = OnCreateWriter(fileName);
                        _writers[key] = writer;
                    }
                }
                finally
                {
                    writer.Flush();
                }
            }
        }
Exemplo n.º 13
0
        /// <inheritdoc />
        protected override bool OnSendInMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_syncRoot)
                {
                    _securityIds.Clear();
                    _suspendedOutMessages.Clear();
                    _suspendedInMessages.Clear();
                }

                break;
            }

            case MessageTypes.OrderPairReplace:
            {
                var pairMsg = (OrderPairReplaceMessage)message;

                var securityId1 = pairMsg.Message1.SecurityId;
                var securityId2 = pairMsg.Message2.SecurityId;

                if (securityId1.Native != null && securityId2.Native != null)
                {
                    break;
                }

                var nativeId1 = GetNativeId(pairMsg, securityId1);

                if (nativeId1 == null)
                {
                    return(true);
                }

                var nativeId2 = GetNativeId(pairMsg, securityId2);

                if (nativeId2 == null)
                {
                    return(true);
                }

                securityId1.Native = nativeId1;
                pairMsg.Message1.ReplaceSecurityId(securityId1);

                securityId2.Native = nativeId2;
                pairMsg.Message2.ReplaceSecurityId(securityId2);
                break;
            }

            case ExtendedMessageTypes.ProcessSuspended:
                ProcessInSuspended(((ProcessSuspendedMessage)message).SecurityId);
                return(true);

            default:
            {
                if (message is ISecurityIdMessage secIdMsg)
                {
                    if (secIdMsg.SecurityId == default)
                    {
                        break;
                    }

                    var securityId = secIdMsg.SecurityId;

                    if (securityId.Native != null)
                    {
                        break;
                    }

                    var native = GetNativeId(message, securityId);

                    if (native == null)
                    {
                        return(true);
                    }

                    securityId.Native = native;
                    message.ReplaceSecurityId(securityId);
                }

                break;
            }
            }

            return(base.OnSendInMessage(message));
        }
Exemplo n.º 14
0
            private void ReloadOrders()
            {
                _versionOrderSet.Clear();

                int countOld = 0, countNew = 0;

                var orders = _connector.Orders.Where(order => order.Id > 0).ToDictionary(order => order.Id);

                var processedOrders = new List <BusinessEntities.Order>();

                foreach (var oecOrder in Oec.Orders)
                {
                    foreach (var ver in oecOrder.Versions)
                    {
                        try
                        {
                            if (orders.ContainsKey(ver.ID))
                            {
                                ++countOld;
                                var order = orders[ver.ID];
                                processedOrders.Add(order);
                                BindOrderToOecOrderVersion(order, ver);

                                if (order.IsInFinalState() && ver.IsInFinalState())
                                {
                                    continue;
                                }

                                order.CopyFromOECOrderVersion(ver);
                                _connector.GetOrder(order.Security, order.Type, order.Id, id => order, o => false);
                            }
                            else
                            {
                                var portfolio = _connector.FindPortfolioByAccount(ver.Order.Account, null);
                                var security  = _connector.FindSecurityByContract(ver.Order.Contract);
                                var vercopy   = ver;
                                var orderType = ver.Type.ToStockSharp();
                                var order     = _connector.GetOrder(security, orderType, ver.ID, id =>
                                {
                                    var ord = _connector.EntityFactory.CreateOrder(security, orderType, vercopy.ID);
                                    ord.Id  = id;
                                    // TODO
                                    //_connector.InitNewOrder(ord);
                                    return(ord);
                                }, ord =>
                                {
                                    ord.Portfolio = portfolio;
                                    ord.Security  = security;
                                    ord.CopyFromOECOrderVersion(vercopy);

                                    return(true);
                                });
                                ++countNew;
                                BindOrderToOecOrderVersion(order, ver);
                                processedOrders.Add(order);
                            }
                        }
                        catch (Exception ex)
                        {
                            var msg = "Ошибка загрузки заявки #{0} ({1}): {2}".Put(ver.ID, ver, ex);
                            _connector.AddErrorLog(msg);
                            _connector.TransactionAdapter.SendOutMessage(new ErrorMessage {
                                Error = ex
                            });
                        }
                    }
                }

                var countFailed = 0;
                // incomplete local orders which weren't found in OEC
                var otherIncompleteOrders = _connector.Orders.Except(processedOrders).Where(order => !order.IsInFinalState());

                foreach (var order in otherIncompleteOrders)
                {
                    ++countFailed;
                    var ordercopy = order;

                    _connector.GetOrder(order.Security, order.Type, order.TransactionId, id => ordercopy, o =>
                    {
                        o.Id     = 0;
                        o.State  = OrderStates.Done;
                        o.Status = OrderStatus.NotDone;
                        _connector.RaiseOrderFailed(o, new OECException("После переподключения заявка была не найдена среди заявок OEC."));

                        return(true);
                    });
                }

                _connector.AddInfoLog("{0} заявок OEC связано с существующими заявками S#; {1} новых заявок загружено из OEC; {2} незавершенных заявок OEC были завершены с ошибкой.", countOld, countNew, countFailed);
            }