public static async Task <IGroupMembersCollectionWithReferencesPage> GetGroupMembersAsync(string groupId) { IGroupMembersCollectionWithReferencesPage members = null; var graphClient = AuthenticationHelper.GetAuthenticatedClient(); try { var group = await graphClient.Groups[groupId].Request().Expand("members").GetAsync(); members = group.Members; foreach (var member in members) { Debug.WriteLine("Member Id:" + member.Id); } } catch (ServiceException e) { Debug.WriteLine("We could not get the group members: " + e.Error.Message); return(null); } return(members); }
public static async Task <bool> AddUserToGroup(string userId, string groupId) { bool userAdded = false; GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); try { User userToAdd = new User { Id = userId }; //The underlying REST call returns a 204 (no content), so we can't retrieve the updated group //with this call. await graphClient.Groups[groupId].Members.References.Request().AddAsync(userToAdd); Debug.WriteLine("Added user " + userId + " to the group: " + groupId); userAdded = true; } catch (ServiceException e) { Debug.WriteLine("We could not add a user to the group: " + e.Error.Message); userAdded = false; } return(userAdded); }
public static async Task <WorkbookRange> ChangeExcelNumberFormatAsync(string fileId) { WorkbookRange workbookRange = null; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); string excelWorksheetId = "ChangeNumberFormat"; string rangeAddress = "E2"; // Forming the JSON for JArray arr = JArray.Parse(@"[['$#,##0.00;[Red]$#,##0.00']]"); // Currency format WorkbookRange dummyWorkbookRange = new WorkbookRange(); dummyWorkbookRange.NumberFormat = arr; workbookRange = await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets[excelWorksheetId] .Range(rangeAddress) .Request() .PatchAsync(dummyWorkbookRange); Debug.WriteLine("Updated the number format of the Excel workbook range: " + workbookRange.Address); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to change the number format: " + e.Error.Message); } return(workbookRange); }
// Creates a new group in the tenant. public static async Task <string> CreateGroupAsync(string groupName) { //JObject jResult = null; string createdGroupId = null; var graphClient = AuthenticationHelper.GetAuthenticatedClient(); try { var group = await graphClient.Groups.Request().AddAsync(new Group { GroupTypes = new List <string> { "Unified" }, DisplayName = groupName, Description = "This group was created by the snippets app.", MailNickname = groupName, MailEnabled = false, SecurityEnabled = false }); createdGroupId = group.Id; Debug.WriteLine("Created group:" + createdGroupId); } catch (ServiceException e) { Debug.WriteLine("We could not create a group: " + e.Error.Message); return(null); } return(createdGroupId); }
// Updates the description of an existing group. public static async Task <bool> UpdateGroupAsync(string groupId) { bool groupUpdated = false; var graphClient = AuthenticationHelper.GetAuthenticatedClient(); try { var groupToUpdate = new Group(); groupToUpdate.Description = "This group was updated by the snippets app."; //The underlying REST call returns a 204 (no content), so we can't retrieve the updated group //with this call. await graphClient.Groups[groupId].Request().UpdateAsync(groupToUpdate); Debug.WriteLine("Updated group:" + groupId); groupUpdated = true; } catch (ServiceException e) { Debug.WriteLine("We could not update the group: " + e.Error.Message); groupUpdated = false; } return(groupUpdated); }
// Creates a folder in the user's root directory. // This does not work with consumer accounts. public static async Task <string> CreateFolderAsync(string folderName) { string createFolderId = null; DriveItem folderToCreate = new DriveItem(); folderToCreate.Name = folderName; var folder = new Folder(); folderToCreate.Folder = folder; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var createdFolder = await graphClient.Me.Drive.Items.Request().AddAsync(folderToCreate); if (createdFolder != null) { createFolderId = createdFolder.Id; Debug.WriteLine("Created folder Id: " + createFolderId); } } catch (ServiceException e) { Debug.WriteLine("We could not create the folder. The request returned this status code: " + e.Error.Message); return(null); } return(createFolderId); }
// Updates the subject of an existing event in the signed-in user's tenant. public static async Task <bool> UpdateEventAsync(string eventId) { bool eventUpdated = false; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var eventToUpdate = new Event(); eventToUpdate.Subject = "Sync of the week"; //eventToUpdate.IsAllDay = true; var updatedEvent = await graphClient.Me.Events[eventId].Request().UpdateAsync(eventToUpdate); if (updatedEvent != null) { Debug.WriteLine("Updated event: " + eventToUpdate.Id); eventUpdated = true; } } catch (ServiceException e) { Debug.WriteLine("We could not update the event: " + e.Error.Message); eventUpdated = false; } return(eventUpdated); }
public static async Task <string> SearchForFileAsync(string fileName) { string fileId = null; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Check that this item hasn't already been created. // https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/item_search IDriveItemSearchCollectionPage searchResults = await graphClient.Me.Drive.Root.Search(fileName).Request().GetAsync(); foreach (var r in searchResults) { if (r.Name == fileName) { fileId = r.Id; } } } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("The search for this file failed: " + e.Error.Message); } return(fileId); }
public static async Task <bool> UnprotectExcelWorksheetAsync(string fileId) { bool worksheetUnProtected = false; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Protect the worksheet. await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets["ProtectWorksheet"] .Protection .Unprotect() .Request() .PostAsync(); worksheetUnProtected = true; Debug.WriteLine("Unprotected the worksheet."); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to unprotect the worksheet: " + e.Error.Message); } return(worksheetUnProtected); }
// Returns information about the signed-in user public static async Task <string> GetMeAsync() { string currentUserName = null; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var currentUserObject = await graphClient.Me.Request().GetAsync(); currentUserName = currentUserObject.DisplayName; if (currentUserName != null) { Debug.WriteLine("Got user: "******"We could not get the current user: " + e.Error.Message); return(null); } return(currentUserName); }
public static async Task <bool> FilterExcelTableValuesAsync(string fileId) { bool tableFiltered = false; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Filter the table. This results in a call to the service. await graphClient.Me.Drive.Items[fileId] .Workbook .Tables["FilterTableValues"] .Columns["1"] // This is a one based index. .Filter .ApplyValuesFilter(JArray.Parse("[\"2\"]")) .Request() .PostAsync(); tableFiltered = true; Debug.WriteLine("Filtered the table."); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to filter the table: " + e.Error.Message); } return(tableFiltered); }
// Gets the signed-in user's drive. public static async Task <string> GetCurrentUserDriveAsync() { string currentUserDriveId = null; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var currentUserDrive = await graphClient.Me.Drive.Request().GetAsync(); currentUserDriveId = currentUserDrive.Id; if (currentUserDriveId != null) { Debug.WriteLine("Got user drive: " + currentUserDriveId); } } catch (ServiceException e) { Debug.WriteLine("We could not get the current user drive: " + e.Error.Message); return(null); } return(currentUserDriveId); }
public static async Task <WorkbookTableRow> AddExcelRowToTableAsync(string fileId) { WorkbookTableRow workbookTableRow = null; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Create the table row to insert. This assumes that the table has 2 columns. // You'll want to make sure you give a JSON array that matches the size of the table. WorkbookTableRow newWorkbookTableRow = new WorkbookTableRow(); newWorkbookTableRow.Index = 0; JArray myArr = JArray.Parse("[[\"ValueA2\",\"ValueA3\"]]"); newWorkbookTableRow.Values = myArr; //// Insert a new row. This results in a call to the service. workbookTableRow = await graphClient.Me.Drive.Items[fileId] .Workbook .Tables["Table1"] .Rows .Request() .AddAsync(newWorkbookTableRow); Debug.WriteLine("Added a row to Table 1."); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to add the table row: " + e.Error.Message); } return(workbookTableRow); }
public static async Task <bool> UploadExcelFileContentAsync(string fileId) { bool fileUploaded = false; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); DriveItem excelDriveItem = null; var assembly = typeof(UserSnippets).GetTypeInfo().Assembly; Stream fileStream = assembly.GetManifestResourceStream("Graph_Xamarin_CS_Snippets.excelTestResource.xlsx"); // Upload content to the file. // https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/item_uploadcontent excelDriveItem = await graphClient.Me.Drive.Items[fileId].Content.Request().PutAsync <DriveItem>(fileStream); if (excelDriveItem != null) { fileUploaded = true; } } catch (ServiceException e) { Debug.WriteLine("We failed to upload the contents of the Excel file: " + e.Error.Message); } return(fileUploaded); }
public static async Task <WorkbookRange> SetExcelFormulaAsync(string fileId) { WorkbookRange workbookRange = null; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Forming the JSON for updating the formula var arr = JArray.Parse(@"[['=A4*B4']]"); // We want to use a dummy workbook object so that we only send the property we want to update. var dummyWorkbookRange = new WorkbookRange(); dummyWorkbookRange.Formulas = arr; workbookRange = await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets["SetFormula"] .Range("C4") .Request() .PatchAsync(dummyWorkbookRange); Debug.WriteLine("Set an Excel formula in this workbook range: " + workbookRange.Address); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to set the formula: " + e.Error.Message); } return(workbookRange); }
// Renames a file in the user's root directory. public static async Task <bool> RenameFileAsync(string fileId, string newFileName) { bool fileRenamed = false; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var fileToRename = new DriveItem(); fileToRename.Name = newFileName; var renamedFile = await graphClient.Me.Drive.Items[fileId].Request().UpdateAsync(fileToRename); if (renamedFile != null) { Debug.WriteLine("Renamed file Id: " + renamedFile.Id); fileRenamed = true; } } catch (ServiceException e) { Debug.WriteLine("We could not rename the file. The request returned this status code: " + e.Error.Message); fileRenamed = false; } return(fileRenamed); }
public static async Task <bool> TrySendMailAsync() { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var currentUser = await graphClient.Me.Request().GetAsync(); return(await UserSnippets.SendMessageAsync( STORY_DATA_IDENTIFIER, DEFAULT_MESSAGE_BODY, currentUser.UserPrincipalName )); }
// Creates a text file in the user's root directory. public static async Task <string> CreateFileAsync(string fileName, string fileContent) { string createdFileId = null; DriveItem fileToCreate = new DriveItem(); //Read fileContent string into a stream that gets passed as the file content byte[] byteArray = Encoding.UTF8.GetBytes(fileContent); MemoryStream fileContentStream = new MemoryStream(byteArray); fileToCreate.Content = fileContentStream; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var createdFile = await graphClient.Me.Drive.Root.ItemWithPath(fileName).Content.Request().PutAsync <DriveItem>(fileContentStream); createdFileId = createdFile.Id; Debug.WriteLine("Created file Id: " + createdFileId); } //Known bug -- file created but ServiceException "Value cannot be null" thrown //Workaround: catch the exception, make sure that it is the one that is expected, get the item and itemID catch (ServiceException se) { if (se.InnerException.Message.Contains("Value cannot be null")) { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var createdFile = await graphClient.Me.Drive.Root.ItemWithPath(fileName).Request().GetAsync(); createdFileId = createdFile.Id; return(createdFileId); } else { Debug.WriteLine("We could not create the file. The request returned this status code: " + se.Message); return(null); } } catch (Exception e) { Debug.WriteLine("We could not create the file. The request returned this status code: " + e.Message); return(null); } return(createdFileId); }
//Excel snippets // Uploads a file and then streams the contents // of an existing spreadsheet into it. You must run this at least once // before running the other Excel snippets. Otherwise, the other snippets // will fail, because they assume the presence of this file. // If you quit the app and run it again 5-10 minutes after uploading // the Excel file, the snippets will likely fail, // because the new file won't be indexed for search yet and the app won't // be able to retrieve the file Id public static async Task <string> UploadExcelFileAsync(string fileName) { string createdFileId = null; try { // First test to determine whether the file exists. Create it if it doesn't. // Don't bother to search if ExcelFileId variable is already populated. if (ExcelFileId != null) { createdFileId = ExcelFileId; } else { createdFileId = await SearchForFileAsync(fileName); } if (createdFileId == null) { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); DriveItem excelWorkbook = new DriveItem() { Name = fileName, File = new Microsoft.Graph.File() }; // Create the Excel file. DriveItem excelWorkbookDriveItem = await graphClient.Me.Drive.Root.Children.Request().AddAsync(excelWorkbook); createdFileId = excelWorkbookDriveItem.Id; bool excelFileUploaded = await UploadExcelFileContentAsync(createdFileId); if (excelFileUploaded) { createdFileId = excelWorkbookDriveItem.Id; Debug.WriteLine("Created Excel file. Name: " + fileName + " Id: " + createdFileId); } } } catch (ServiceException e) { Debug.WriteLine("We could not create the file: " + e.Error.Message); } // Store the file id so that you don't have to search for it // in subsequent snippets. ExcelFileId = createdFileId; return(createdFileId); }
// Updates the subject of an existing event in the signed-in user's tenant. public static async Task <bool> SendMessageAsync( string Subject, string Body, string RecipientAddress ) { bool emailSent = false; //Create recipient list List <Recipient> recipientList = new List <Recipient>(); recipientList.Add(new Recipient { EmailAddress = new EmailAddress { Address = RecipientAddress.Trim() } }); //Create message var email = new Message { Body = new ItemBody { Content = Body, ContentType = BodyType.Html, }, Subject = Subject, ToRecipients = recipientList, }; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); await graphClient.Me.SendMail(email, true).Request().PostAsync(); Debug.WriteLine("Message sent"); emailSent = true; } catch (ServiceException e) { Debug.WriteLine("We could not send the message. The request returned this status code: " + e.Error.Message); emailSent = false; } return(emailSent); }
public static async Task <WorkbookTable> AddExcelTableToUsedRangeAsync(string fileId) { WorkbookTable workbookTable = null; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Get the used range of this worksheet. This results in a call to the service. WorkbookRange workbookRange = await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets["AddTableUsedRange"] .UsedRange() .Request() .GetAsync(); // Create the dummy workbook object. Must use the AdditionalData property for this. WorkbookTable dummyWorkbookTable = new WorkbookTable(); Dictionary <string, object> requiredPropsCreatingTableFromRange = new Dictionary <string, object>(); requiredPropsCreatingTableFromRange.Add("address", workbookRange.Address); requiredPropsCreatingTableFromRange.Add("hasHeaders", false); dummyWorkbookTable.AdditionalData = requiredPropsCreatingTableFromRange; // Create a table based on the address of the workbookRange. // This results in a call to the service. // https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/tablecollection_add workbookTable = await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets["AddTableUsedRange"] .Tables .Add(false, workbookRange.Address) .Request() .PostAsync(); Debug.WriteLine("Added this Excel table to the used range: " + workbookTable.Name); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to add the table to the used range: " + e.Error.Message); } return(workbookTable); }
// Adds content to a file in the user's root directory. public static async Task <bool> UpdateFileAsync(string fileId, string fileContent) { bool fileUpdated = false; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); //Read fileContent string into a stream that gets passed as the file content byte[] byteArray = Encoding.UTF8.GetBytes(fileContent); MemoryStream fileContentStream = new MemoryStream(byteArray); var updatedFile = await graphClient.Me.Drive.Items[fileId].Content.Request().PutAsync <DriveItem>(fileContentStream);; if (updatedFile != null) { Debug.WriteLine("Updated file Id: " + updatedFile.Id); fileUpdated = true; } } //Known bug -- file created but ServiceException "Value cannot be null" thrown //Workaround: catch the exception, make sure that it is the one that is expected, return true catch (ServiceException se) { if (se.InnerException.Message.Contains("Value cannot be null")) { return(true); } else { Debug.WriteLine("We could not create the file. The request returned this status code: " + se.Message); return(false); } } catch (Exception e) { Debug.WriteLine("We could not update the file. The request returned this status code: " + e.Message); fileUpdated = false; } return(fileUpdated); }
public static async Task <WorkbookChart> CreateExcelChartFromTableAsync(string fileId) { WorkbookChart workbookChart = null; if (fileId == null) { Debug.WriteLine("Please upload the excelTestResource.xlsx file by running the Upload XL File snippet."); return(workbookChart); } else { try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Get the table range. WorkbookRange tableRange = await graphClient.Me.Drive.Items[fileId] .Workbook .Tables["CreateChartFromTable"] // Set in excelTestResource.xlsx .Range() .Request() .GetAsync(); // Create a chart based on the table range. workbookChart = await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets["CreateChartFromTable"] // Set in excelTestResource.xlsx .Charts .Add("ColumnStacked", "Auto", tableRange.Address) .Request() .PostAsync(); Debug.WriteLine("Created the Excel chart: " + workbookChart.Name); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to create the Excel chart: " + e.Error.Message); } return(workbookChart); } }
// Downloads the content of an existing file. public static async Task <Stream> DownloadFileAsync(string fileId) { Stream fileContent = null; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var downloadedFile = await graphClient.Me.Drive.Items[fileId].Content.Request().GetAsync(); fileContent = downloadedFile; Debug.WriteLine("Downloaded file content for file: " + fileId); } catch (ServiceException e) { Debug.WriteLine("We could not download the file. The request returned this status code: " + e.Error.Message); return(null); } return(fileContent); }
public static async Task <WorkbookRange> UpdateExcelRangeAsync(string fileId) { WorkbookRange workbookRange = null; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // GET https://graph.microsoft.com/beta/me/drive/items/012KW42LDENXUUPCMYQJDYX3CLZMORQKGT/workbook/worksheets/Sheet1/Range(address='A1') WorkbookRange rangeToUpdate = await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets["GetUpdateRange"] // Set in excelTestResource.xlsx .Range("A1") .Request() .GetAsync(); // Forming the JSON for the updated values JArray arr = rangeToUpdate.Values as JArray; JArray arrInner = arr[0] as JArray; arrInner[0] = $"{arrInner[0] + "Updated"}"; // JToken // Create a dummy WorkbookRange object so that we only PATCH the values we want to update. WorkbookRange dummyWorkbookRange = new WorkbookRange(); dummyWorkbookRange.Values = arr; // Update the range values. workbookRange = await graphClient.Me.Drive.Items[fileId] .Workbook .Worksheets["GetUpdateRange"] // Set in excelTestResource.xlsx .Range("A1") .Request() .PatchAsync(dummyWorkbookRange); Debug.WriteLine("Updated the Excel workbook range: " + workbookRange.Address); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to get the Excel workbook range: " + e.Error.Message); } return(workbookRange); }
// Deletes an existing event in the signed-in user's tenant. public static async Task <bool> DeleteEventAsync(string eventId) { bool eventDeleted = false; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var eventToDelete = await graphClient.Me.Events[eventId].Request().GetAsync(); await graphClient.Me.Events[eventId].Request().DeleteAsync(); Debug.WriteLine("Deleted event: " + eventToDelete.Id); eventDeleted = true; } catch (ServiceException e) { Debug.WriteLine("We could not delete the event: " + e.Error.Message); eventDeleted = false; } return(eventDeleted); }
// Gets the signed-in user's manager. // This snippet doesn't work with personal accounts. public static async Task <string> GetCurrentUserManagerAsync() { string currentUserManagerId = null; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var currentUserManager = await graphClient.Me.Manager.Request().GetAsync(); currentUserManagerId = currentUserManager.Id; Debug.WriteLine("Got manager: " + currentUserManagerId); } catch (ServiceException e) { Debug.WriteLine("We could not get the current user's manager: " + e.Error.Message); return(null); } return(currentUserManagerId); }
public static async Task <WorkbookFunctionResult> AbsExcelFunctionAsync(string fileId) { WorkbookFunctionResult workbookFunctionResult = null; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); // Get the absolute value of -10 JToken inputNumber = JToken.Parse("-10"); workbookFunctionResult = await graphClient.Me.Drive.Items[fileId].Workbook.Functions.Abs(inputNumber).Request().PostAsync(); Debug.WriteLine("Ran the Excel ABS function: " + workbookFunctionResult.Value); } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to run the ABS function: " + e.Error.Message); } return(workbookFunctionResult); }
// Deletes a file in the user's root directory. public static async Task <bool> DeleteFileAsync(string fileId) { bool fileDeleted = false; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); var fileToDelete = graphClient.Me.Drive.Items[fileId].Request().GetAsync(); await graphClient.Me.Drive.Items[fileId].Request().DeleteAsync(); Debug.WriteLine("Deleted file Id: " + fileToDelete.Id); fileDeleted = true; } catch (ServiceException e) { Debug.WriteLine("We could not delete the file. The request returned this status code: " + e.Error.Message); fileDeleted = false; } return(fileDeleted); }
public static async Task <bool> DeleteExcelFileAsync(string fileId) { bool fileDeleted = false; try { GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient(); if (fileId != null) { DriveItem w = await graphClient.Me.Drive.Items[fileId].Request().GetAsync(); List <Option> headers = new List <Option>() { new HeaderOption("if-match", "*") }; // Delete the workbook. // https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/item_delete await graphClient.Me.Drive.Items[fileId].Request(headers).DeleteAsync(); fileDeleted = true; Debug.WriteLine("Deleted the file: " + fileId); ExcelFileId = null; } else { Debug.WriteLine("We couldn't find the Excel file, so we didn't delete it."); } } catch (Microsoft.Graph.ServiceException e) { Debug.WriteLine("We failed to delete the Excel file: " + e.Error.Message); } return(fileDeleted); }