public async Task <TransferResponse> Transferir(TransferRequest request) { try { TransferResponse response = new TransferResponse(); var transferenciaDebitoEntity = _mapper.Map <TransferenciaDebitoEntity>(request); var transferenciaCreditoEntity = _mapper.Map <TrasnferenciaCreditoEntity>(request); transferenciaDebitoEntity.Validate(transferenciaDebitoEntity); transferenciaCreditoEntity.Validate(transferenciaCreditoEntity); if (!(transferenciaDebitoEntity.Valid || transferenciaCreditoEntity.Valid)) { _notification.AddNotifications(transferenciaDebitoEntity.ValidationResult); _notification.AddNotifications(transferenciaCreditoEntity.ValidationResult); return(response); } response.Data.TransactionId = await _transferenciaService.Transferir(transferenciaDebitoEntity, transferenciaCreditoEntity); return(response); } catch (Exception ex) { throw ex; } }
public TransferResponse TransferMoney(TransferRequest transferRequest) { string content = JsonConvert.SerializeObject(transferRequest); string path = "/vendorwallet/TransferNotification"; string response = Post(content, path); TransferResponse balanceResponse = JsonConvert.DeserializeObject <TransferResponse>(response); return(balanceResponse); }
public void Completes_Wait_For_TransferResponse(string username, IPEndPoint endpoint, int token, int fileSize) { var(handler, mocks) = GetFixture(username, endpoint); var msg = new TransferResponse(token, fileSize).ToByteArray(); handler.HandleMessageRead(mocks.PeerConnection.Object, msg); mocks.Waiter.Verify(m => m.Complete(new WaitKey(MessageCode.Peer.TransferResponse, username, token), It.Is <TransferResponse>(r => r.Token == token)), Times.Once); }
public void RequestTransferFullBalance() { BoletoFacil boletoFacil = GetBoletoFacil(); Transfer transfer = Transfer; TransferResponse response = boletoFacil.RequestTransfer(transfer); Assert.IsNotNull(response); Assert.IsTrue(response.Success); }
public void Parse_Throws_MessageException_On_Code_Mismatch() { var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.BrowseRequest) .Build(); var ex = Record.Exception(() => TransferResponse.FromByteArray(msg)); Assert.NotNull(ex); Assert.IsType <MessageException>(ex); }
public void Parse_Throws_MessageReadException_On_Missing_Data() { var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.TransferResponse) .Build(); var ex = Record.Exception(() => TransferResponse.FromByteArray(msg)); Assert.NotNull(ex); Assert.IsType <MessageReadException>(ex); }
public void RequestTransferPartialBalance() { BoletoFacil boletoFacil = GetBoletoFacil(); Transfer transfer = Transfer; transfer.Amount = 78.67m; TransferResponse response = boletoFacil.RequestTransfer(transfer); Assert.IsNotNull(response); Assert.IsTrue(response.Success); }
public static Transfer SellBitcoins(Quantity quantity, APIKey apiKey) { TransferResponse transferResponse = (TransferResponse)PostResource( "sells", quantity, typeof(Quantity), typeof(TransferResponse), apiKey ); return(transferResponse.Transfer); }
public async Task <HttpResponseMessage> RequestTransfer(string to, string value, string from, string password) { TransferResponse response = new TransferResponse() { source = new EtherAccount() { publicAddress = from }, destination = new EtherAccount() { publicAddress = to } }; try { // Connect to Web3 var web3Client = new Web3(blockchainRPCEndpoint); var web3GethClient = new Web3Geth(web3Client.Client); //Ensure Sender has Enough Balance to send response.source = await(await GetBalance(response.source.publicAddress)).Content.ReadAsAsync <EtherAccount>(); if (Convert.ToInt64(response.source.balance) < Convert.ToInt64(value)) { return(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Insufficient Balance")); } // Unlock Sender Address bool accountUnlocked = await web3GethClient.Personal.UnlockAccount.SendRequestAsync(from, password, 60000); if (!accountUnlocked) { return(Request.CreateErrorResponse(HttpStatusCode.NonAuthoritativeInformation, "Sender Account Authentication invaid")); } //Start Miners bool minerStarted = await web3GethClient.Miner.Start.SendRequestAsync(6); response.receipt = (await TransferRPC(web3GethClient, from, web3Client.Convert.ToWei(value), to)).FirstOrDefault(); //Get Account Balance response.source = await(await GetBalance(response.source.publicAddress)).Content.ReadAsAsync <EtherAccount>(); response.destination = await(await GetBalance(response.destination.publicAddress)).Content.ReadAsAsync <EtherAccount>(); } catch (Exception ex) { Trace.TraceError(ex.StackTrace); return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message)); } return(Request.CreateResponse <TransferResponse>(response)); }
public void Rejects_TransferRequest_Upload_Request_If_Transfer_Is_Not_Tracked(string username, IPEndPoint endpoint, int token, string filename) { var(handler, mocks) = GetFixture(username, endpoint); var request = new TransferRequest(TransferDirection.Upload, token, filename); var message = request.ToByteArray(); handler.HandleMessageRead(mocks.PeerConnection.Object, message); var expected = new TransferResponse(token, string.Empty).ToByteArray(); mocks.PeerConnection.Verify(m => m.WriteAsync(It.Is <byte[]>(b => b.Matches(expected)), It.IsAny <CancellationToken?>()), Times.Once); }
public void Parse_Returns_Expected_Data_When_Upload_Allowed(int token) { var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.TransferResponse) .WriteInteger(token) .WriteByte(0x1) .Build(); var response = TransferResponse.FromByteArray(msg); Assert.Equal(token, response.Token); Assert.True(response.IsAllowed); }
public void Instantiates_With_The_Proper_Data_When_Allowed(int token, long size) { TransferResponse response = null; Exception ex = null; ex = Record.Exception(() => response = new TransferResponse(token, size)); Assert.Null(ex); Assert.Equal(token, response.Token); Assert.True(response.IsAllowed); Assert.Equal(size, response.FileSize); }
public void Writes_TransferResponse_On_Successful_QueueDownload_Invocation(string username, IPEndPoint endpoint, int token, string filename) { var options = new SoulseekClientOptions(enqueueDownloadAction: (u, f, i) => Task.CompletedTask); var(handler, mocks) = GetFixture(username, endpoint, options); var message = new TransferRequest(TransferDirection.Download, token, filename).ToByteArray(); var expected = new TransferResponse(token, "Queued").ToByteArray(); handler.HandleMessageRead(mocks.PeerConnection.Object, message); mocks.PeerConnection.Verify(m => m.WriteAsync(It.Is <byte[]>(b => Encoding.UTF8.GetString(b) == Encoding.UTF8.GetString(expected)), null), Times.Once); }
private static OperationHistoryModel Convert(TransferResponse src, string customerId) { return(new OperationHistoryModel { Type = src.ReceiverCustomerId == customerId ? HistoryOperationType.ReceiveTransfer : HistoryOperationType.SendTransfer, Timestamp = src.Timestamp, Amount = src.Amount, OtherSideCustomerEmail = src.ReceiverCustomerId == customerId ? src.SenderCustomerEmail : src.ReceiverCustomerEmail, }); }
public void Instantiates_With_The_Proper_Data_When_Disallowed(int token, string msg) { TransferResponse response = null; Exception ex = null; ex = Record.Exception(() => response = new TransferResponse(token, msg)); Assert.Null(ex); Assert.Equal(token, response.Token); Assert.False(response.IsAllowed); Assert.Equal(msg, response.Message); }
public void Parse_Returns_Expected_Data_When_Disallowed(int token, string message) { var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.TransferResponse) .WriteInteger(token) .WriteByte(0x0) .WriteString(message) .Build(); var response = TransferResponse.FromByteArray(msg); Assert.Equal(token, response.Token); Assert.False(response.IsAllowed); Assert.Equal(message, response.Message); }
public void Writes_TransferResponse_And_QueueFailedResponse_On_Failed_QueueDownload_Invocation(string username, IPAddress ip, int port, int token, string filename) { var options = new ClientOptions(queueDownloadAction: (u, f, i, p) => throw new Exception()); var(handler, mocks) = GetFixture(username, ip, port, options); var message = new TransferRequest(TransferDirection.Download, token, filename).ToByteArray(); var expectedTransferResponse = new TransferResponse(token, "Enqueue failed due to internal error.").ToByteArray(); var expectedQueueFailedResponse = new QueueFailedResponse(filename, "Enqueue failed due to internal error.").ToByteArray(); handler.HandleMessage(mocks.PeerConnection.Object, message); mocks.PeerConnection.Verify(m => m.WriteAsync(It.Is <byte[]>(b => Encoding.UTF8.GetString(b) == Encoding.UTF8.GetString(expectedTransferResponse)), null), Times.Once); mocks.PeerConnection.Verify(m => m.WriteAsync(It.Is <byte[]>(b => Encoding.UTF8.GetString(b) == Encoding.UTF8.GetString(expectedQueueFailedResponse)), null), Times.Once); }
public void Parse_Returns_Expected_Data_When_Allowed(int token, long size) { var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.TransferResponse) .WriteInteger(token) .WriteByte(0x1) .WriteLong(size) .Build(); var response = TransferResponse.Parse(msg); Assert.Equal(token, response.Token); Assert.True(response.Allowed); Assert.Equal(size, response.FileSize); }
private void TransferFromWallet(int source) { TransferResponse response = _vendorApi.TransferMoney(new TransferRequest { Currency = _userSession.Currency, DomainId = _domainId, UserId = _userSession.UserID, IpAddress = _userSession.IP, UserName = _userSession.Username, Source = source }); GmLogger.Instance.Trace(string.Format( "Casino wallet money balance double check, transfer money for vendor:{0}, received result is {1}", _vendor, response.Success)); }
public void Writes_TransferResponse_And_QueueFailedResponse_On_Rejected_QueueDownload_Invocation(string username, IPEndPoint endpoint, int token, string filename, string rejectMessage) { var options = new SoulseekClientOptions(enqueueDownloadAction: (u, f, i) => { throw new DownloadEnqueueException(rejectMessage); }); var(handler, mocks) = GetFixture(username, endpoint, options); var message = new TransferRequest(TransferDirection.Download, token, filename).ToByteArray(); var expectedTransferResponse = new TransferResponse(token, rejectMessage).ToByteArray(); var expectedQueueFailedResponse = new EnqueueFailedResponse(filename, rejectMessage).ToByteArray(); handler.HandleMessageRead(mocks.PeerConnection.Object, message); mocks.PeerConnection.Verify(m => m.WriteAsync(It.Is <byte[]>(b => Encoding.UTF8.GetString(b) == Encoding.UTF8.GetString(expectedTransferResponse)), null), Times.Once); mocks.PeerConnection.Verify(m => m.WriteAsync(It.Is <byte[]>(b => Encoding.UTF8.GetString(b) == Encoding.UTF8.GetString(expectedQueueFailedResponse)), null), Times.Once); }
public TransferResponse Transfer(TransferRequest request) { TransferResponse response = new TransferResponse(); try { _bankAccountService.Transfer(request.AccountIdTo, request.AccountIdFrom, request.Amount); response.Success = true; } catch (InsufficientFundsException) { response.Message = "There is not enough funds in account no: " + request.AccountIdFrom.ToString(); response.Success = false; } return(response); }
public void ToByteArray_Constructs_The_Correct_Message_When_Allowed(int token, long size) { var a = new TransferResponse(token, size); var msg = a.ToByteArray(); var reader = new MessageReader <MessageCode.Peer>(msg); var code = reader.ReadCode(); Assert.Equal(MessageCode.Peer.TransferResponse, code); // length + code + token + allowed + size Assert.Equal(4 + 4 + 4 + 1 + 8, msg.Length); Assert.Equal(token, reader.ReadInteger()); Assert.Equal(1, reader.ReadByte()); Assert.Equal(size, reader.ReadLong()); }
public async Task <TransferResponse> TransferDataAsync(int port, Guid id) { var response = new TransferResponse(); try { response = await $"https://localhost:{port}" .AppendPathSegments("api", "bank", "transfer", id) .GetJsonAsync <TransferResponse>(); } catch (FlurlHttpException ex) { response.Description = ex.Message; } return(response); }
private void TransferToWallet(int target) { TransferResponse response = _vendorApi.TransferMoney(new TransferRequest { Currency = _userSession.Currency, DomainId = _domainId, UserId = _userSession.UserID, IpAddress = _userSession.IP, UserName = _userSession.Username, Target = target, }); if (!response.Success) { throw new CeException(String.Format("Transfer to {0}. Cannot open game of vendor {0} because {1}{2}", target, response.VendorError, response.Message)); } }
public TransferResponse Transfer(TransferRequest request) { // Map DTOs to Domain Models Mapper.CreateMap<AccountDTO, Account>(); Account from = Mapper.Map<AccountDTO, Account>(request.From); Account to = Mapper.Map<AccountDTO, Account>(request.To); TransferResponse response = new TransferResponse(); decimal amount = request.Amount; try { // Use domain model or domain service(if exist) to apply bussiness rules. from.TransferMoney(to, amount); // Use repository to prepare updates to the database _accountRepository.Update(from); _accountRepository.Update(to); // Use unit of work to commit the updates to the database _unitOfWork.Commit(); } catch (NoBalanceException) { response.IsSuccessful = false; response.Message = "Unable to transfer amount! Account doesn't have any balance."; return response; } catch (DataConcurrencyException) { response.IsSuccessful = false; response.Message = "Unable to transfer amount! Data is modified after getting from the database. Please try again."; return response; } catch (Exception) { response.IsSuccessful = false; response.Message = "Unable to transfer amount! If problem persist, please contact system administrator."; return response; } response.IsSuccessful = true; response.Message = "Transfer successful."; return response; }
public void ToByteArray_Constructs_The_Correct_Message_When_Disallowed(int token, string message) { var a = new TransferResponse(token, message); var msg = a.ToByteArray(); var code = new MessageReader <MessageCode.Peer>(msg).ReadCode(); Assert.Equal(MessageCode.Peer.TransferResponse, code); // length + code + token + allowed + message len + message Assert.Equal(4 + 4 + 4 + 1 + 4 + message.Length, msg.Length); var reader = new MessageReader <MessageCode.Peer>(msg); Assert.Equal(token, reader.ReadInteger()); Assert.Equal(0, reader.ReadByte()); Assert.Equal(message, reader.ReadString()); }
/// /// Get the json fault message from the provided error /// protected virtual Message GetJsonFaultMessage( MessageVersion version, Exception error) { TransferResponse response; if (error is SerializationException) { response = new TransferResponse("Wrong request format"); } else { response = new TransferResponse("Unauthorized"); } var faultMessage = Message.CreateMessage(version, "", response, new DataContractJsonSerializer(response.GetType())); return(faultMessage); }
public void Completes_Wait_For_TransferResponse(string username, IPAddress ip, int port, int token, int fileSize) { var conn = new Mock <IMessageConnection>(); conn.Setup(m => m.Username) .Returns(username); conn.Setup(m => m.IPAddress) .Returns(ip); conn.Setup(m => m.Port) .Returns(port); var waiter = new Mock <IWaiter>(); var msg = new TransferResponse(token, fileSize).ToMessage(); var s = new SoulseekClient("127.0.0.1", 1, waiter: waiter.Object); s.InvokeMethod("PeerConnection_MessageRead", conn.Object, msg); waiter.Verify(m => m.Complete(new WaitKey(MessageCode.Peer.TransferResponse, username, token), It.Is <TransferResponse>(r => r.Token == token)), Times.Once); }
public TransferResponse Transfer(TransferRequest request) { var response = new TransferResponse(); response.Success = true; try { _accountService.Transfer(request.AccountToNo, request.AccountFromNo, request.Amount); } catch (InsufficientFundsException) { response.Success = false; response.Message = $"Insufficient funds in account number {request.AccountFromNo}"; } catch (Exception ex) { response.Success = false; response.Message = "Unexpected error"; } return(response); }
public async Task <IActionResult> Transfer([FromBody] TransferReqeuest request) { int statusCode = 200; TransferResponse result = null; string error = null; try { result = await _actionService.Transfer(request.FromIBAN, request.ToIBAN, request.Amount, request.Remark); } catch (ArgumentException e) { Log.Error($"Failed to transfer", e); statusCode = 400; error = e.Message; } catch (Exception e) { Log.Error($"Failed to transfer", e); statusCode = 500; error = e.Message; } return(CreateResponse(statusCode, result, error)); }
/// <summary> /// Handles incoming messages. /// </summary> /// <param name="sender">The <see cref="IMessageConnection"/> instance from which the message originated.</param> /// <param name="message">The message.</param> public async void HandleMessageRead(object sender, byte[] message) { var connection = (IMessageConnection)sender; var code = new MessageReader <MessageCode.Peer>(message).ReadCode(); Diagnostic.Debug($"Peer message received: {code} from {connection.Username} ({connection.IPEndPoint}) (id: {connection.Id})"); try { switch (code) { case MessageCode.Peer.SearchResponse: var searchResponse = SearchResponseFactory.FromByteArray(message); if (SoulseekClient.Searches.TryGetValue(searchResponse.Token, out var search)) { search.TryAddResponse(searchResponse); } break; case MessageCode.Peer.BrowseResponse: var browseWaitKey = new WaitKey(MessageCode.Peer.BrowseResponse, connection.Username); try { SoulseekClient.Waiter.Complete(browseWaitKey, BrowseResponseFactory.FromByteArray(message)); } catch (Exception ex) { SoulseekClient.Waiter.Throw(browseWaitKey, new MessageReadException("The peer returned an invalid browse response", ex)); throw; } break; case MessageCode.Peer.InfoRequest: UserInfo outgoingInfo; try { outgoingInfo = await SoulseekClient.Options .UserInfoResponseResolver(connection.Username, connection.IPEndPoint).ConfigureAwait(false); } catch (Exception ex) { outgoingInfo = await new SoulseekClientOptions() .UserInfoResponseResolver(connection.Username, connection.IPEndPoint).ConfigureAwait(false); Diagnostic.Warning($"Failed to resolve user info response: {ex.Message}", ex); } await connection.WriteAsync(outgoingInfo.ToByteArray()).ConfigureAwait(false); break; case MessageCode.Peer.BrowseRequest: BrowseResponse browseResponse; try { browseResponse = await SoulseekClient.Options.BrowseResponseResolver(connection.Username, connection.IPEndPoint).ConfigureAwait(false); } catch (Exception ex) { browseResponse = await new SoulseekClientOptions() .BrowseResponseResolver(connection.Username, connection.IPEndPoint).ConfigureAwait(false); Diagnostic.Warning($"Failed to resolve browse response: {ex.Message}", ex); } await connection.WriteAsync(browseResponse.ToByteArray()).ConfigureAwait(false); break; case MessageCode.Peer.FolderContentsRequest: var folderContentsRequest = FolderContentsRequest.FromByteArray(message); Directory outgoingFolderContents = null; try { outgoingFolderContents = await SoulseekClient.Options.DirectoryContentsResponseResolver( connection.Username, connection.IPEndPoint, folderContentsRequest.Token, folderContentsRequest.DirectoryName).ConfigureAwait(false); } catch (Exception ex) { Diagnostic.Warning($"Failed to resolve directory contents response: {ex.Message}", ex); } if (outgoingFolderContents != null) { var folderContentsResponseMessage = new FolderContentsResponse(folderContentsRequest.Token, outgoingFolderContents); await connection.WriteAsync(folderContentsResponseMessage.ToByteArray()).ConfigureAwait(false); } break; case MessageCode.Peer.FolderContentsResponse: var folderContentsResponse = FolderContentsResponse.FromByteArray(message); SoulseekClient.Waiter.Complete(new WaitKey(MessageCode.Peer.FolderContentsResponse, connection.Username, folderContentsResponse.Token), folderContentsResponse.Directory); break; case MessageCode.Peer.InfoResponse: var incomingInfo = UserInfoResponseFactory.FromByteArray(message); SoulseekClient.Waiter.Complete(new WaitKey(MessageCode.Peer.InfoResponse, connection.Username), incomingInfo); break; case MessageCode.Peer.TransferResponse: var transferResponse = TransferResponse.FromByteArray(message); SoulseekClient.Waiter.Complete(new WaitKey(MessageCode.Peer.TransferResponse, connection.Username, transferResponse.Token), transferResponse); break; case MessageCode.Peer.QueueDownload: var queueDownloadRequest = EnqueueDownloadRequest.FromByteArray(message); var(queueRejected, queueRejectionMessage) = await TryEnqueueDownloadAsync(connection.Username, connection.IPEndPoint, queueDownloadRequest.Filename).ConfigureAwait(false); if (queueRejected) { await connection.WriteAsync(new EnqueueFailedResponse(queueDownloadRequest.Filename, queueRejectionMessage).ToByteArray()).ConfigureAwait(false); } else { await TrySendPlaceInQueueAsync(connection, queueDownloadRequest.Filename).ConfigureAwait(false); } break; case MessageCode.Peer.TransferRequest: var transferRequest = TransferRequest.FromByteArray(message); if (transferRequest.Direction == TransferDirection.Upload) { if (!SoulseekClient.Downloads.IsEmpty && SoulseekClient.Downloads.Values.Any(d => d.Username == connection.Username && d.Filename == transferRequest.Filename)) { SoulseekClient.Waiter.Complete(new WaitKey(MessageCode.Peer.TransferRequest, connection.Username, transferRequest.Filename), transferRequest); } else { // reject the transfer with an empty reason. it was probably cancelled, but we can't be sure. await connection.WriteAsync(new TransferResponse(transferRequest.Token, string.Empty).ToByteArray()).ConfigureAwait(false); } } else { var(transferRejected, transferRejectionMessage) = await TryEnqueueDownloadAsync(connection.Username, connection.IPEndPoint, transferRequest.Filename).ConfigureAwait(false); if (transferRejected) { await connection.WriteAsync(new TransferResponse(transferRequest.Token, transferRejectionMessage).ToByteArray()).ConfigureAwait(false); await connection.WriteAsync(new EnqueueFailedResponse(transferRequest.Filename, transferRejectionMessage).ToByteArray()).ConfigureAwait(false); } else { await connection.WriteAsync(new TransferResponse(transferRequest.Token, "Queued").ToByteArray()).ConfigureAwait(false); await TrySendPlaceInQueueAsync(connection, transferRequest.Filename).ConfigureAwait(false); } } break; case MessageCode.Peer.QueueFailed: var queueFailedResponse = EnqueueFailedResponse.FromByteArray(message); SoulseekClient.Waiter.Throw(new WaitKey(MessageCode.Peer.TransferRequest, connection.Username, queueFailedResponse.Filename), new TransferRejectedException(queueFailedResponse.Message)); break; case MessageCode.Peer.PlaceInQueueResponse: var placeInQueueResponse = PlaceInQueueResponse.FromByteArray(message); SoulseekClient.Waiter.Complete(new WaitKey(MessageCode.Peer.PlaceInQueueResponse, connection.Username, placeInQueueResponse.Filename), placeInQueueResponse); break; case MessageCode.Peer.PlaceInQueueRequest: var placeInQueueRequest = PlaceInQueueRequest.FromByteArray(message); await TrySendPlaceInQueueAsync(connection, placeInQueueRequest.Filename).ConfigureAwait(false); break; case MessageCode.Peer.UploadFailed: var uploadFailedResponse = UploadFailed.FromByteArray(message); var msg = $"Download of {uploadFailedResponse.Filename} reported as failed by {connection.Username}"; var download = SoulseekClient.Downloads.Values.FirstOrDefault(d => d.Username == connection.Username && d.Filename == uploadFailedResponse.Filename); if (download != null) { SoulseekClient.Waiter.Throw(new WaitKey(MessageCode.Peer.TransferRequest, download.Username, download.Filename), new TransferException(msg)); } Diagnostic.Debug(msg); break; default: Diagnostic.Debug($"Unhandled peer message: {code} from {connection.Username} ({connection.IPEndPoint}); {message.Length} bytes"); break; } } catch (Exception ex) { Diagnostic.Warning($"Error handling peer message: {code} from {connection.Username} ({connection.IPEndPoint}); {ex.Message}", ex); } }
public TransferResponse Transfer(TransferRequest request) { TransferResponse response = new TransferResponse(); try { _bankAccountService.Transfer(request.AccountIdTo, request.AccountIdFrom, request.Amount); response.Success = true; } catch (InsufficientFundsException) { response.Message = "There is not enough funds in account no: " + request.AccountIdFrom.ToString(); response.Success = false; } return response; }