Exemplo n.º 1
0
        public sealed override ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken token)
        {
            ValueTask <int> result;

            if (token.IsCancellationRequested)
            {
#if NETSTANDARD2_1
                result = new (Task.FromCanceled <int>(token));
#else
                result = ValueTask.FromCanceled <int>(token);
#endif
            }
            else
            {
                try
                {
                    result = new(Read(buffer.Span));
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new (Task.FromException <int>(e));
#else
                    result = ValueTask.FromException <int>(e);
#endif
                }
            }

            return(result);
        }
Exemplo n.º 2
0
        protected override ValueTask CloseAsyncCore(ConnectionCloseMethod method, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ValueTask.FromCanceled(cancellationToken));
            }

            try
            {
                if (method != ConnectionCloseMethod.GracefulShutdown)
                {
                    // Dispose must be called first in order to cause a connection reset,
                    // as NetworkStream.Dispose() will call Shutdown(Both).
                    _stream.Socket.Dispose();
                }

                _stream.Dispose();
            }
            catch (SocketException socketException)
            {
                return(ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(NetworkErrorHelper.MapSocketException(socketException))));
            }
            catch (Exception ex)
            {
                return(ValueTask.FromException(ex));
            }

            return(default);
Exemplo n.º 3
0
        ValueTask IAsyncBinaryWriter.WriteBigIntegerAsync(BigInteger value, LengthFormat lengthFormat, EncodingContext context, string?format, IFormatProvider?provider, CancellationToken token)
        {
            ValueTask result;

            if (token.IsCancellationRequested)
            {
#if NETSTANDARD2_1
                result = new (Task.FromCanceled(token));
#else
                result = ValueTask.FromCanceled(token);
#endif
            }
            else
            {
                result = new();
                try
                {
                    writer.WriteBigInteger(value, lengthFormat, in context, format, provider);
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new (Task.FromException(e));
#else
                    result = ValueTask.FromException(e);
#endif
                }
            }

            return(result);
        }
Exemplo n.º 4
0
        private unsafe ValueTask <int> ReadAsyncInternal(Memory <byte> destination, CancellationToken cancellationToken = default)
        {
            if (!CanRead)
            {
                ThrowHelper.ThrowNotSupportedException_UnreadableStream();
            }

            long positionBefore = _filePosition;

            if (CanSeek)
            {
                long len = Length;
                if (positionBefore + destination.Length > len)
                {
                    destination = positionBefore <= len?
                                  destination.Slice(0, (int)(len - positionBefore)) :
                                      default;
                }

                // When using overlapped IO, the OS is not supposed to
                // touch the file pointer location at all.  We will adjust it
                // ourselves, but only in memory. This isn't threadsafe.
                _filePosition += destination.Length;
            }

            (SafeFileHandle.ValueTaskSource? vts, int errorCode) = RandomAccess.QueueAsyncReadFile(_fileHandle, destination, positionBefore, cancellationToken);
            return(vts != null
                ? new ValueTask <int>(vts, vts.Version)
                : (errorCode == 0) ? ValueTask.FromResult(0) : ValueTask.FromException <int>(HandleIOError(positionBefore, errorCode)));
        }
Exemplo n.º 5
0
        internal static ValueTask SerializeAsync <T, TWriter>(TWriter writer, string typeId, T obj, CancellationToken token)
            where TWriter : notnull, IAsyncBinaryWriter
        {
            // try to get synchronous writer
            var       bufferWriter = writer.TryGetBufferWriter();
            ValueTask result;

            if (bufferWriter is null)
            {
                // slow path - delegate allocation is required and arguments must be packed
                result = writer.WriteAsync(SerializeToJson, (typeId, obj), token);
            }
            else
            {
                // fast path - synchronous serialization
                result = new();
                try
                {
                    Serialize(typeId, obj, bufferWriter);
                }
                catch (Exception e)
                {
                    result = ValueTask.FromException(e);
                }
            }

            return(result);
Exemplo n.º 6
0
        protected override ValueTask CloseAsyncCore(ConnectionCloseMethod method, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ValueTask.FromCanceled(cancellationToken));
            }

            try
            {
                if (method != ConnectionCloseMethod.GracefulShutdown)
                {
                    // Dispose must be called first in order to cause a connection reset,
                    // as NetworkStream.Dispose() will call Shutdown(Both).
                    _socket.Dispose();
                }

                // Since CreatePipe() calls CreateStream(), so _stream should be present even in the pipe case:
                _stream?.Dispose();
            }
            catch (SocketException socketException)
            {
                return(ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(socketException)));
            }
            catch (Exception ex)
            {
                return(ValueTask.FromException(ex));
            }

            return(default);
Exemplo n.º 7
0
        ValueTask IAsyncBinaryWriter.WriteAsync <T>(T value, CancellationToken token)
        {
            ValueTask result;

            if (token.IsCancellationRequested)
            {
#if NETSTANDARD2_1
                result = new (Task.FromCanceled(token));
#else
                result = ValueTask.FromCanceled(token);
#endif
            }
            else
            {
                result = new();
                try
                {
                    writer.Write(in value);
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new (Task.FromException(e));
#else
                    result = ValueTask.FromException(e);
#endif
                }
            }

            return(result);
        }
Exemplo n.º 8
0
        ValueTask IAsyncBinaryWriter.WriteAsync <TArg>(Action <TArg, IBufferWriter <byte> > writer, TArg arg, CancellationToken token)
        {
            ValueTask result;

            if (token.IsCancellationRequested)
            {
#if NETSTANDARD2_1
                result = new (Task.FromCanceled(token));
#else
                result = ValueTask.FromCanceled(token);
#endif
            }
            else
            {
                result = new();
                try
                {
                    writer(arg, this.writer);
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new (Task.FromException(e));
#else
                    result = ValueTask.FromException(e);
#endif
                }
            }

            return(result);
        }
Exemplo n.º 9
0
        ValueTask IAsyncBinaryReader.SkipAsync(int length, CancellationToken token)
        {
            if (length < 0)
#if NETSTANDARD2_1
            { return(new ValueTask(Task.FromException(new ArgumentOutOfRangeException(nameof(length))))); }
#else
            { return(ValueTask.FromException(new ArgumentOutOfRangeException(nameof(length)))); }
#endif

            if (!stream.CanSeek)
            {
                return(SkipSlowAsync(length, token));
            }

            var current = stream.Position;
            if (current + length > stream.Length)
#if NETSTANDARD2_1
            { return(new ValueTask(Task.FromException(new EndOfStreamException()))); }
#else
            { return(ValueTask.FromException(new EndOfStreamException())); }
#endif

            stream.Position = length + current;
            return(new ValueTask());
        }
Exemplo n.º 10
0
        /// <inheritdoc/>
        public override ValueTask <ValueHttpRequest?> CreateNewRequestAsync(HttpPrimitiveVersion version, HttpVersionPolicy versionPolicy, CancellationToken cancellationToken = default)
        {
            if (_writeBuffer.ActiveLength != 0 || _responseContentBytesRemaining != 0)
            {
                return(ValueTask.FromException <ValueHttpRequest?>(ExceptionDispatchInfo.SetCurrentStackTrace(new Exception("Unable to create request stream with a request already pending."))));
            }

            if (version.Major != 1)
            {
                if (versionPolicy == HttpVersionPolicy.RequestVersionOrLower)
                {
                    version = HttpPrimitiveVersion.Version11;
                }
                return(ValueTask.FromException <ValueHttpRequest?>(ExceptionDispatchInfo.SetCurrentStackTrace(new Exception($"Unable to create request for HTTP/{version.Major}.{version.Minor} with a {nameof(Http1Connection)}."))));
            }

            _writeState                = WriteState.Unstarted;
            _requestIsChunked          = true;
            _responseHasContentLength  = false;
            _responseIsChunked         = false;
            _readingFirstResponseChunk = false;
            _readFunc = s_ReadResponse;

            if (Interlocked.Exchange(ref _request, null) is Http1Request request)
            {
                request.Init(this, version);
            }
            else
            {
                request = new Http1Request(this, version);
            }

            return(new ValueTask <ValueHttpRequest?>(request.GetValueRequest()));
        }
Exemplo n.º 11
0
        ValueTask IAsyncBinaryWriter.WriteAsync(ReadOnlyMemory <char> chars, EncodingContext context, LengthFormat?lengthFormat, CancellationToken token)
        {
            ValueTask result;

            if (token.IsCancellationRequested)
            {
#if NETSTANDARD2_1
                result = new (Task.FromCanceled(token));
#else
                result = ValueTask.FromCanceled(token);
#endif
            }
            else
            {
                result = new();
                try
                {
                    writer.WriteString(chars.Span, in context, lengthFormat: lengthFormat);
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new (Task.FromException(e));
#else
                    result = ValueTask.FromException(e);
#endif
                }
            }

            return(result);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Reads bytes from stream and puts them into the buffer
        /// </summary>
        /// <param name="buffer">Buffer to read the bytes to.</param>
        /// <param name="cancellationToken">Token that can be used to cancel this operation.</param>
        public override ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken = default)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ValueTask.FromCanceled <int>(cancellationToken));
            }

            try
            {
                // ReadAsync(Memory<byte>,...) needs to delegate to an existing virtual to do the work, in case an existing derived type
                // has changed or augmented the logic associated with reads.  If the Memory wraps an array, we could delegate to
                // ReadAsync(byte[], ...), but that would defeat part of the purpose, as ReadAsync(byte[], ...) often needs to allocate
                // a Task<int> for the return value, so we want to delegate to one of the synchronous methods.  We could always
                // delegate to the Read(Span<byte>) method, and that's the most efficient solution when dealing with a concrete
                // UnmanagedMemoryStream, but if we're dealing with a type derived from UnmanagedMemoryStream, Read(Span<byte>) will end up delegating
                // to Read(byte[], ...), which requires it to get a byte[] from ArrayPool and copy the data.  So, we special-case the
                // very common case of the Memory<byte> wrapping an array: if it does, we delegate to Read(byte[], ...) with it,
                // as that will be efficient in both cases, and we fall back to Read(Span<byte>) if the Memory<byte> wrapped something
                // else; if this is a concrete UnmanagedMemoryStream, that'll be efficient, and only in the case where the Memory<byte> wrapped
                // something other than an array and this is an UnmanagedMemoryStream-derived type that doesn't override Read(Span<byte>) will
                // it then fall back to doing the ArrayPool/copy behavior.
                return(new ValueTask <int>(
                           MemoryMarshal.TryGetArray(buffer, out ArraySegment <byte> destinationArray) ?
                           Read(destinationArray.Array !, destinationArray.Offset, destinationArray.Count) :
                           Read(buffer.Span)));
            }
            catch (Exception ex)
            {
                return(ValueTask.FromException <int>(ex));
            }
        }
Exemplo n.º 13
0
        ValueTask ISupplier <ReadOnlyMemory <byte>, CancellationToken, ValueTask> .Invoke(ReadOnlyMemory <byte> input, CancellationToken token)
        {
            ValueTask result;

            if (token.IsCancellationRequested)
            {
#if NETSTANDARD2_1
                result = new (Task.FromCanceled(token));
#else
                result = ValueTask.FromCanceled(token);
#endif
            }
            else
            {
                result = new();
                try
                {
                    writer.Write(input.Span);
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new (Task.FromException(e));
#else
                    result = ValueTask.FromException(e);
#endif
                }
            }

            return(result);
        }
Exemplo n.º 14
0
        ValueTask IAsyncBinaryWriter.WriteBigIntegerAsync(BigInteger value, bool littleEndian, LengthFormat?lengthFormat, CancellationToken token)
        {
            ValueTask result;

            if (token.IsCancellationRequested)
            {
#if NETSTANDARD2_1
                result = new (Task.FromCanceled(token));
#else
                result = ValueTask.FromCanceled(token);
#endif
            }
            else
            {
                result = new();
                try
                {
                    writer.WriteBigInteger(in value, littleEndian, lengthFormat);
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new (Task.FromException(e));
#else
                    result = ValueTask.FromException(e);
#endif
                }
            }

            return(result);
        }
        public override ValueTask <ValueWebSocketReceiveResult> ReceiveAsync(Memory <byte> buffer, CancellationToken cancellationToken)
        {
            try
            {
                WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validReceiveStates);

                Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}");
                lock (ReceiveAsyncLock) // synchronize with receives in CloseAsync
                {
                    ThrowIfOperationInProgress(_lastReceiveAsync.IsCompleted);

                    ValueTask <ValueWebSocketReceiveResult> receiveValueTask = ReceiveAsyncPrivate <ValueWebSocketReceiveResultGetter, ValueWebSocketReceiveResult>(buffer, cancellationToken);
                    if (receiveValueTask.IsCompletedSuccessfully)
                    {
                        _lastReceiveAsync = receiveValueTask.Result.MessageType == WebSocketMessageType.Close ? s_cachedCloseTask : Task.CompletedTask;
                        return(receiveValueTask);
                    }

                    // We need to both store the last receive task and return it, but we can't do that with a ValueTask,
                    // as that could result in consuming it multiple times.  Instead, we use AsTask to consume it just once,
                    // and then store that Task and return a new ValueTask that wraps it. (It would be nice in the future
                    // to avoid this AsTask as well; currently it's used both for error detection and as part of close tracking.)
                    Task <ValueWebSocketReceiveResult> receiveTask = receiveValueTask.AsTask();
                    _lastReceiveAsync = receiveTask;
                    return(new ValueTask <ValueWebSocketReceiveResult>(receiveTask));
                }
            }
            catch (Exception exc)
            {
                return(ValueTask.FromException <ValueWebSocketReceiveResult>(exc));
            }
        }
Exemplo n.º 16
0
        /// <inheritdoc/>
        ValueTask IDataTransferObject.WriteToAsync <TWriter>(TWriter writer, CancellationToken token)
        {
            ValueTask result;
            var       bufferWriter = writer.TryGetBufferWriter();

            if (bufferWriter is null)
            {
                result = writer.WriteAsync(Content.AsMemory(), Type.GetEncoding(), null, token);
            }
            else
            {
                // fast path - serialize synchronously
                result = new();
                try
                {
                    bufferWriter.WriteString(Content.AsSpan(), Type.GetEncoding());
                }
                catch (Exception e)
                {
#if NETSTANDARD2_1
                    result = new(Task.FromException(e));
#else
                    result = ValueTask.FromException(e);
#endif
                }
            }

            return(result);
        }
Exemplo n.º 17
0
        /// <inheritdoc/>
        public sealed override ValueTask <Connection> ConnectAsync(EndPoint?endPoint, IConnectionProperties?options = null, CancellationToken cancellationToken = default)
        {
            if (options == null || !options.TryGet(out DnsEndPointWithProperties? httpOptions))
            {
                return(ValueTask.FromException <Connection>(ExceptionDispatchInfo.SetCurrentStackTrace(new HttpRequestException($"{nameof(SocketsHttpConnectionFactory)} requires a {nameof(DnsEndPointWithProperties)} property."))));
            }

            return(EstablishConnectionAsync(httpOptions !.InitialRequest, endPoint, options, cancellationToken));
        }
Exemplo n.º 18
0
 protected override ValueTask SendBufferAsync(ReadOnlyMemory <byte> buffer, bool isBinary, bool isEOM, CancellationToken cancellationToken)
 {
     if (IsClosed())
     {
         return(ValueTask.FromException(new OperationCanceledException()));
     }
     return(_webSocket.SendAsync(buffer, isBinary ? WebSocketMessageType.Binary : WebSocketMessageType.Text, isEOM,
                                 cancellationToken));
 }
Exemplo n.º 19
0
        public override ValueTask WriteAsync(ReadOnlyMemory <byte> buffer, CancellationToken cancellationToken = default)
        {
            long writeOffset = CanSeek ? Interlocked.Add(ref _filePosition, buffer.Length) - buffer.Length : -1;

            (SafeFileHandle.OverlappedValueTaskSource? vts, int errorCode) = RandomAccess.QueueAsyncWriteFile(_fileHandle, buffer, writeOffset, cancellationToken);
            return(vts != null
                ? new ValueTask(vts, vts.Version)
                : (errorCode == 0) ? ValueTask.CompletedTask : ValueTask.FromException(HandleIOError(writeOffset, errorCode)));
        }
Exemplo n.º 20
0
        /// <inheritdoc/>
        public override ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken = default)
        {
            if (!CanRead)
            {
                return(ValueTask.FromException <int>(new NotSupportedException(SR.NotSupported_UnreadableStream)));
            }

            return(ReadAsyncInternal(buffer, cancellationToken));
        }
Exemplo n.º 21
0
 protected override ValueTask <ValueWebSocketReceiveResult> ReceiveBufferAsync(Memory <byte> buffer, CancellationToken cancellationToken)
 {
     if (_webSocket.State == WebSocketState.CloseSent)
     {
         //Allow receiving the close response.
         return(_webSocket.ReceiveAsync(buffer, cancellationToken));
     }
     if (IsClosed())
     {
         return(ValueTask.FromException <ValueWebSocketReceiveResult>(new OperationCanceledException()));
     }
     return(_webSocket.ReceiveAsync(buffer, cancellationToken));
 }
Exemplo n.º 22
0
 public override ValueTask DisposeAsync()
 {
     try
     {
         ValueTask vt = _leaveStreamOpen ?
                        new ValueTask(_innerStream.FlushAsync()) :
                        _innerStream.DisposeAsync();
         GC.SuppressFinalize(this);
         return(vt);
     }
     catch (Exception exc)
     {
         return(ValueTask.FromException(exc));
     }
 }
Exemplo n.º 23
0
        private static unsafe ValueTask <int> ReadFileScatterAsync(SafeFileHandle handle, MemoryHandle pinnedSegments, int bytesToRead, long fileOffset, CancellationToken cancellationToken)
        {
            handle.EnsureThreadPoolBindingInitialized();

            SafeFileHandle.OverlappedValueTaskSource vts = handle.GetOverlappedValueTaskSource();
            try
            {
                NativeOverlapped *nativeOverlapped = vts.PrepareForOperation(Memory <byte> .Empty, fileOffset);
                Debug.Assert(pinnedSegments.Pointer != null);

                if (Interop.Kernel32.ReadFileScatter(handle, (long *)pinnedSegments.Pointer, bytesToRead, IntPtr.Zero, nativeOverlapped) == 0)
                {
                    // The operation failed, or it's pending.
                    int errorCode = FileStreamHelpers.GetLastWin32ErrorAndDisposeHandleIfInvalid(handle);
                    switch (errorCode)
                    {
                    case Interop.Errors.ERROR_IO_PENDING:
                        // Common case: IO was initiated, completion will be handled by callback.
                        // Register for cancellation now that the operation has been initiated.
                        vts.RegisterForCancellation(cancellationToken);
                        break;

                    case Interop.Errors.ERROR_HANDLE_EOF:     // logically success with 0 bytes read (read at end of file)
                    case Interop.Errors.ERROR_BROKEN_PIPE:
                        // EOF on a pipe. Callback will not be called.
                        // We clear the overlapped status bit for this special case (failure
                        // to do so looks like we are freeing a pending overlapped later).
                        nativeOverlapped->InternalLow = IntPtr.Zero;
                        vts.Dispose();
                        return(ValueTask.FromResult(0));

                    default:
                        // Error. Callback will not be called.
                        vts.Dispose();
                        return(ValueTask.FromException <int>(Win32Marshal.GetExceptionForWin32Error(errorCode, handle.Path)));
                    }
                }
            }
            catch
            {
                vts.Dispose();
                throw;
            }

            // Completion handled by callback.
            vts.FinishedScheduling();
            return(new ValueTask <int>(vts, vts.Version));
        }
Exemplo n.º 24
0
        protected virtual ValueTask <DbTransaction> BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ValueTask.FromCanceled <DbTransaction>(cancellationToken));
            }

            try
            {
                return(new ValueTask <DbTransaction>(BeginDbTransaction(isolationLevel)));
            }
            catch (Exception e)
            {
                return(ValueTask.FromException <DbTransaction>(e));
            }
        }
Exemplo n.º 25
0
    public ValueTask <int> ReceiveAsync(Socket socket, Memory <byte> buffer)
    {
        SetBuffer(buffer);

        if (socket.ReceiveAsync(this))
        {
            return(new ValueTask <int>(this, 0));
        }

        var bytesTransferred = BytesTransferred;
        var error            = SocketError;

        return(error == SocketError.Success ?
               new ValueTask <int>(bytesTransferred) :
               ValueTask.FromException <int>(CreateException(error)));
    }
Exemplo n.º 26
0
        private ValueTask <int> CompleteSynchronously()
        {
            // Completing synchronously, so we don't need to preserve the
            // async bits.
            Reset();

            var error = SocketError;

            if (error == SocketError.Success)
            {
                // Return a ValueTask directly, in a no-alloc operation.
                return(new ValueTask <int>(BytesTransferred));
            }

            // Fail synchronously.
            return(ValueTask.FromException <int>(new SocketException((int)error)));
        }
Exemplo n.º 27
0
 private static Func <ValueTask <MessageBuffer>, ValueTask> CreateHandlerFunc(Func <ValueTask <T>, ValueTask> task)
 {
     return(async msgTask =>
     {
         ValueTask <T> t;
         try
         {
             var msg = await msgTask;
             t = ValueTask.FromResult(MessageSerializer.Deserialize <T>(msg));
         }
         catch (Exception e)
         {
             t = ValueTask.FromException <T>(e);
         }
         await task(t);
     });
 }
Exemplo n.º 28
0
            public override ValueTask WriteAsync(ReadOnlyMemory <byte> buffer, CancellationToken ignored) // token ignored as it comes from SendAsync
            {
                BytesWritten += buffer.Length;

                if (BytesWritten > _contentLength)
                {
                    return(ValueTask.FromException(new HttpRequestException(SR.net_http_content_write_larger_than_content_length)));
                }

                // Have the connection write the data, skipping the buffer. Importantly, this will
                // force a flush of anything already in the buffer, i.e. any remaining request headers
                // that are still buffered.
                HttpConnection connection = GetConnectionOrThrow();

                Debug.Assert(connection._currentRequest != null);
                return(connection.WriteAsync(buffer, async: true));
            }
Exemplo n.º 29
0
            public override ValueTask WriteAsync(ReadOnlyMemory <byte> buffer, CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(ValueTask.FromCanceled(cancellationToken));
                }

                HttpConnection?connection = _connection;

                if (connection == null)
                {
                    return(ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException(SR.ObjectDisposed_StreamClosed))));
                }

                if (buffer.Length == 0)
                {
                    return(default);
Exemplo n.º 30
0
 public ValueTask UpdateAsync(TEntity item)
 {
     try
     {
         DbContext.Entry(item).State = EntityState.Modified;
         return(ValueTask.CompletedTask);
     }
     catch (DbUpdateException e)
     {
         logger.LogError(e, "Unable To Update State Of {0}", typeof(TEntity).Name);
         if (e.InnerException is not null)
         {
             logger.LogError(e.InnerException, "Update Entity Inner Exception");
         }
         return(ValueTask.FromException(new EntityTransactionException("Unable to update the entity", e)));
     }
 }