public DataLakeStoreFileSystemManagementHelper(TestBase testBase) { this.testBase = testBase; resourceManagementClient = this.testBase.GetResourceManagementClient(); dataLakeStoreManagementClient = this.testBase.GetDataLakeStoreManagementClient(); dataLakeStoreFileSystemClient = this.testBase.GetDataLakeStoreFileSystemManagementClient(); }
public async static Task<string> GetLatestAPIVersion(ResourceManagementClient client, string resourceId, string apiVersion = null) { if (apiVersion == null) { var parameters = new Microsoft.Azure.Management.Resources.Models.ProviderListParameters(); var listProvidersResponse = await client.Providers.ListAsync(parameters).ConfigureAwait(continueOnCapturedContext: false); var identity = GetIdentityFromId(resourceId, apiVersion); var provider = listProvidersResponse.Providers.Where(x => x.Namespace.Equals(identity.ResourceProviderNamespace)).FirstOrDefault(); if (provider == null) { throw new InvalidOperationException("This is not a valid resource provider namespace"); } var type = provider.ResourceTypes.Where(x => x.Name.Equals(identity.ResourceType)).FirstOrDefault(); if (type == null) { throw new InvalidOperationException("This is not a valid resource type"); } apiVersion = type.ApiVersions.OrderByDescending(x => x).FirstOrDefault(); } return apiVersion; }
protected void EnsureClientsInitialized(bool useSPN = false) { if (!m_initialized) { lock (m_lock) { if (!m_initialized) { var handler = new RecordedDelegatingHandler { StatusCodeToReturn = HttpStatusCode.OK }; if (useSPN) { m_ResourcesClient = ComputeManagementTestUtilities.GetResourceManagementClientWithSpn(handler); m_CrpClient = ComputeManagementTestUtilities.GetComputeManagementClientWithSpn(handler); m_SrpClient = ComputeManagementTestUtilities.GetStorageManagementClientSpn(handler); m_NrpClient = ComputeManagementTestUtilities.GetNetworkResourceProviderClientSpn(handler); } else { m_ResourcesClient = ComputeManagementTestUtilities.GetResourceManagementClient(handler); m_CrpClient = ComputeManagementTestUtilities.GetComputeManagementClient(handler); m_SrpClient = ComputeManagementTestUtilities.GetStorageManagementClient(handler); m_NrpClient = ComputeManagementTestUtilities.GetNetworkResourceProviderClient(handler); } m_subId = m_CrpClient.Credentials.SubscriptionId; m_location = ComputeManagementTestUtilities.DefaultLocation; } } } }
private static Tuple<string, string> GetAllResourceNameAndLocation(EventData eventEntry, string resourceGroupName, string resourceUri, ResourceManagementClient resclient) { Tuple<string, string> resultSet = new Tuple<string, string>(string.Empty, string.Empty); if (!string.IsNullOrWhiteSpace(resourceGroupName) && !string.IsNullOrWhiteSpace(resourceUri)) { try { ResourceListParameters reslist = new ResourceListParameters(); reslist.ResourceGroupName = eventEntry.ResourceGroupName; ResourceListResult resresult = resclient.Resources.List(reslist); foreach (GenericResourceExtended resource in resresult.Resources) { if (resource.Id == eventEntry.ResourceUri) { resultSet = new Tuple<string, string>(resource.Name, resource.Location); break; } } } catch { return resultSet; } } return resultSet; }
private const double days = -10; //max = -90 (90 days of logs is stored by audit logs) static void Main(string[] args) { Console.WriteLine("Starting operations log export."); string token = GetAuthorizationHeader(); TokenCloudCredentials credentials = new TokenCloudCredentials(SubscriptionID, token); InsightsClient client = new InsightsClient(credentials); DateTime endDateTime = DateTime.Now; DateTime startDateTime = endDateTime.AddDays(days); string filterString = FilterString.Generate<ListEventsForResourceProviderParameters>(eventData => (eventData.EventTimestamp >= startDateTime) && (eventData.EventTimestamp <= endDateTime)); EventDataListResponse response = client.EventOperations.ListEvents(filterString, selectedProperties: null); List<EventData> logList = new List<EventData>(response.EventDataCollection.Value); while (!string.IsNullOrEmpty(response.EventDataCollection.NextLink)) { Console.WriteLine($"Retrieving page {response.EventDataCollection.NextLink}"); response = client.EventOperations.ListEventsNext(response.EventDataCollection.NextLink); logList.AddRange(response.EventDataCollection.Value); } ResourceManagementClient resClient = new ResourceManagementClient(credentials); Console.WriteLine($"Page retrieval completed, preparing to write to a file {CSVExportNamePath}."); ExportOpsLogToCSV(logList, resClient); Console.WriteLine("Export completed."); Console.WriteLine("Press any key to exit"); Console.ReadLine(); }
public DataLakeAnalyticsManagementHelper(TestBase testBase) { this.testBase = testBase; resourceManagementClient = this.testBase.GetResourceManagementClient(); storageManagementClient = this.testBase.GetStorageManagementClient(); dataLakeStoreManagementClient = this.testBase.GetDataLakeStoreManagementClient(); }
private static void ExportOpsLogToCSV(IList<EventData> eventDataList, ResourceManagementClient resclient) { using (StreamWriter file = new StreamWriter(CSVExportNamePath)) { file.WriteLine("SubscriptionId,EventTimeStamp,EventDate,EventDataId,CorrelationId,EventName,Level," + "ResourceGroupName,ResourceProviderName,ResourceUri,ResourceName,ResourceLocation," + "Status,Caller,OperationId,OperationName,OperationRP,OperationResType,OperationType," + "Description,Title,Service,Region,Transcript,IncidentId,IncidentType"); foreach(EventData eventEntry in eventDataList) { Tuple<string, string> resourceNameUriPair = GetAllResourceNameAndLocation(eventEntry, eventEntry.ResourceGroupName, eventEntry.ResourceUri, resclient); Tuple<string, string, string> operationNameTrio = ParseOperationName(eventEntry); Tuple<string, string, string, string, string, string> resourceProviderSextet = GetResourceProviderName(eventEntry); DateTime convertedTimeStamp = eventEntry.EventTimestamp.ToUniversalTime(); file.WriteLine($"{eventEntry.SubscriptionId},{convertedTimeStamp},{convertedTimeStamp.Date},{eventEntry.EventDataId?.Replace(',', ';')}" + $",{eventEntry.CorrelationId?.Replace(',', ';')},{eventEntry.CorrelationId?.Replace(',', ';')},{eventEntry.EventName.Value?.Replace(',', ';')}" + $",{eventEntry.Level.ToString()},{eventEntry.ResourceGroupName?.Replace(',', ';')},{eventEntry.ResourceProviderName.Value?.Replace(',', ';')}" + $",{eventEntry.ResourceUri?.Replace(',', ';')},{resourceNameUriPair.Item1},{resourceNameUriPair.Item2},{eventEntry.Status.Value?.Replace(',', ';')}" + $",{eventEntry.Status.Value?.Replace(',', ';')},{eventEntry.Caller?.Replace(',', ';')},{eventEntry.OperationId},{eventEntry.OperationName.Value?.Replace(',', ';')}" + $",{operationNameTrio.Item1},{operationNameTrio.Item2},{operationNameTrio.Item3},{eventEntry.Description?.Replace(',', ';').Replace(System.Environment.NewLine, string.Empty)}" + $",{resourceProviderSextet.Item1},{resourceProviderSextet.Item2},{resourceProviderSextet.Item3},{resourceProviderSextet.Item4}" + $",{resourceProviderSextet.Item5},{resourceProviderSextet.Item6}"); } } }
public static ResourceGroupExtended CreateResourceGroup( SubscriptionCloudCredentials creds, string name, string location ) { var resourceMgmtClient = new ResourceManagementClient( creds ); var resourceGroupsResponse = resourceMgmtClient.ResourceGroups.CreateOrUpdate( name, new ResourceGroup { Location = location } ); return resourceGroupsResponse.ResourceGroup; }
/// <summary> /// Creates a new resource group with the specified name /// If one already exists then it gets updated /// </summary> /// <param name="resourcesClient"></param> public static void CreateResourceGroup(string rgname, ResourceManagementClient resourcesClient) { var resourceGroup = resourcesClient.ResourceGroups.CreateOrUpdate( rgname, new ResourceGroup { Location = DefaultLocation }); }
public ResourceGroupHelper(SubscriptionCloudCredentials credentials) { _client = new ResourceManagementClient(credentials); if (!IsProviderRegistered(_client.Providers.List(null), "Micorsoft.Network")) { _client.Providers.Register("Microsoft.Network"); } }
protected override bool CheckExistence() { using (var resourceClient = new ResourceManagementClient(GetCredentials())) { var existenceResult = resourceClient.ResourceGroups.CheckExistenceAsync(Parameters.Tenant.SiteName).Result; Parameters.Properties.ResourceGroupExists = existenceResult.Exists; return existenceResult.Exists; } }
public DataLakeAnalyticsCatalogManagementHelper(TestBase testBase) { this.testBase = testBase; resourceManagementClient = ClientManagementUtilities.GetResourceManagementClient(this.testBase); dataLakeStoreManagementClient = ClientManagementUtilities.GetDataLakeStoreManagementClient(this.testBase); dataLakeAnalyticsManagementClient = ClientManagementUtilities.GetDataLakeAnalyticsManagementClient(this.testBase); dataLakeAnalyticsJobManagementClient = ClientManagementUtilities.GetDataLakeAnalyticsJobManagementClient(this.testBase); }
public EndpointsCommunicator(AzureSubscription subscription) { if (subscription != Subscription) { Subscription = subscription; SqlClient = null; StorageClient = null; ResourcesClient = null; } }
public static string CreateResourceGroup(ResourceManagementClient resourcesClient, string rgname) { var resourceGroup = resourcesClient.ResourceGroups.CreateOrUpdate( rgname, new ResourceGroup { Location = DefaultLocation }); return rgname; }
/// <summary> /// Initializes the service clients and the logging utility /// </summary> protected void InitializeAzureBackupCmdlet() { var cloudServicesClient = AzureSession.ClientFactory.CreateClient<CloudServiceManagementClient>(DefaultContext, AzureEnvironment.Endpoint.ResourceManager); ServiceClientAdapter = new ServiceClientAdapter(cloudServicesClient.Credentials, cloudServicesClient.BaseUri); WriteDebug("InsideRestore. going to create ResourceManager Client"); RmClient = AzureSession.ClientFactory.CreateClient<ResourcesNS.ResourceManagementClient>(DefaultContext, AzureEnvironment.Endpoint.ResourceManager); WriteDebug("Client Created successfully"); Logger.Instance = new Logger(WriteWarning, WriteDebug, WriteVerbose, ThrowTerminatingError); }
/// <summary> /// Initializes new instance of the <see cref="SchedulerClient"/> class. /// </summary> /// <param name="context">The Azure context reference.</param> public SchedulerClient(AzureContext context) { this.SchedulerManagementClient = AzureSession.ClientFactory.CreateArmClient<SchedulerManagementClient>(context, AzureEnvironment.Endpoint.ResourceManager); this._resourceManagementClient = AzureSession.ClientFactory.CreateClient<ResourceManagementClient>(context, AzureEnvironment.Endpoint.ResourceManager); ProviderResourceType providerResourceType= _resourceManagementClient.Providers.Get(Constants.ProviderNamespace).Provider.ResourceTypes.First((resourceType) => resourceType.Name.Equals(Constants.ResourceType, StringComparison.InvariantCultureIgnoreCase)); _availableRegions = providerResourceType != null ? providerResourceType.Locations : null; this.SchedulerManagementClient.SubscriptionId = context.Subscription.Id.ToString(); }
/// <summary> /// Initializes the service clients and the logging utility /// </summary> protected void InitializeAzureBackupCmdlet() { ServiceClientAdapter = new ServiceClientAdapter(DefaultContext); WriteDebug("InsideRestore. going to create ResourceManager Client"); RmClient = AzureSession.ClientFactory.CreateClient <ResourcesNS.ResourceManagementClient>(DefaultContext, AzureEnvironment.Endpoint.ResourceManager); WriteDebug("Client Created successfully"); Logger.Instance = new Logger(WriteWarning, WriteDebug, WriteVerbose, ThrowTerminatingError); }
protected override bool CreateOrUpdate() { var created = true; try { using (var client = new ResourceManagementClient(GetCredentials())) { // Skip if exists if (!CheckExistence()) { // Build deployment parameters var deployment = new Deployment { Properties = new DeploymentProperties { Mode = DeploymentMode.Incremental, Template = GetTemplate(), } }; // Run deployment var result = client.Deployments.CreateOrUpdateAsync(Parameters.Tenant.SiteName, "Microsoft.DocumentDB", deployment).Result; // Wait for deployment to finish for (var i = 0; i < 30; i++) { var deploymentStatus = client.Deployments.GetAsync(Parameters.Tenant.SiteName, "Microsoft.DocumentDB").Result; if (deploymentStatus.Deployment.Properties.ProvisioningState == ProvisioningState.Succeeded.ToString()) { break; } Thread.Sleep(30000); } Console.WriteLine(result.StatusCode); } // Find the Account Keys SetAccountKeys(); } } catch (Exception ex) { created = false; Message = ex.InnerException != null ? ex.InnerException.Message : ex.Message; } return created; }
public static ResourceManagementClient GetResourceManagementClient(RecordedDelegatingHandler handler) { if (IsTestTenant) { ResourceManagementClient resourcesClient = new ResourceManagementClient(GetCreds()); return resourcesClient; } else { handler.IsPassThrough = true; return TestBase.GetServiceClient<ResourceManagementClient>(new CSMTestEnvironmentFactory()).WithHandler(handler); } }
public static ResourceGroupExtended[] GetResourceGroups( SubscriptionCloudCredentials creds ) { var resourceMgmtClient = new ResourceManagementClient( creds ); var resourceGroupsResponse = resourceMgmtClient.ResourceGroups.ListAsync( new ResourceGroupListParameters( ) ).Result; int currentGroup = 0, resourceGroupsCount = resourceGroupsResponse.ResourceGroups.Count; ResourceGroupExtended[] resourceGroups = new ResourceGroupExtended[ resourceGroupsCount ]; foreach( var group in resourceGroupsResponse.ResourceGroups ) { resourceGroups[ currentGroup++ ] = group; } return resourceGroups; }
private static string GetKeyVaultLocation(ResourceManagementClient resourcesClient) { var providers = resourcesClient.Providers.Get("Microsoft.KeyVault"); var location = providers.Provider.ResourceTypes.Where( (resType) => { if (resType.Name == "vaults") return true; else return false; } ).First().Locations.FirstOrDefault(); return location.ToLowerInvariant().Replace(" ", ""); }
/// <summary> /// Ensures that a resource group with the specified name exists. If it does not, will attempt to create one. /// </summary> /// <param name="resourceManagementClient">The resource manager client.</param> /// <param name="resourceGroupName">The name of the resource group.</param> /// <param name="resourceGroupLocation">The resource group location. Required when creating a new resource group.</param> private static void EnsureResourceGroupExists(ResourceManagementClient resourceManagementClient, string resourceGroupName, string resourceGroupLocation) { if (resourceManagementClient.ResourceGroups.CheckExistence(resourceGroupName) != true) { Console.WriteLine(string.Format("Creating resource group '{0}' in location '{1}'", resourceGroupName, resourceGroupLocation)); var resourceGroup = new ResourceGroup(); resourceGroup.Location = resourceGroupLocation; resourceManagementClient.ResourceGroups.CreateOrUpdate(resourceGroupName, resourceGroup); } else { Console.WriteLine(string.Format("Using existing resource group '{0}'", resourceGroupName)); } }
/// <summary> /// Starts a template deployment. /// </summary> /// <param name="resourceManagementClient">The resource manager client.</param> /// <param name="resourceGroupName">The name of the resource group.</param> /// <param name="deploymentName">The name of the deployment.</param> /// <param name="templateFileContents">The template file contents.</param> /// <param name="parameterFileContents">The parameter file contents.</param> private static void DeployTemplate(ResourceManagementClient resourceManagementClient, string resourceGroupName, string deploymentName, JObject templateFileContents, JObject parameterFileContents) { Console.WriteLine(string.Format("Starting template deployment '{0}' in resource group '{1]'", deploymentName, resourceGroupName)); var deployment = new Deployment(); deployment.Properties = new DeploymentProperties { Mode = DeploymentMode.Incremental, Template = templateFileContents, Parameters = parameterFileContents }; var deploymentResult = resourceManagementClient.Deployments.CreateOrUpdate(resourceGroupName, deploymentName, deployment); Console.WriteLine(string.Format("Deployment status: {0}", deploymentResult.Properties.ProvisioningState)); }
/// <summary> /// Get a default resource location for a given resource type /// </summary> /// <param name="client">The resource management client</param> /// <param name="resourceType">The type of resource to create</param> /// <returns>A location where this resource type is supported for the current subscription</returns> public static string GetResourceLocation(ResourceManagementClient client, string resourceType) { string location = null; string[] parts = resourceType.Split('/'); string providerName = parts[0]; var provider = client.Providers.Get(providerName); foreach (var resource in provider.Provider.ResourceTypes) { if (string.Equals(resource.Name, parts[1], StringComparison.OrdinalIgnoreCase)) { location = resource.Locations.LastOrDefault<string>(); } } return location; }
public static string CreateResourceGroup(ResourceManagementClient resourcesClient, string rgname, string location = "") { if (string.IsNullOrEmpty(location)) { location = DefaultLocation; } var resourceGroup = resourcesClient.ResourceGroups.CreateOrUpdate( rgname, new ResourceGroup { Location = location }); return rgname; }
/// <summary> /// Get a default resource location for a given resource type /// </summary> /// <param name="client">The resource management client</param> /// <param name="resourceType">The type of resource to create</param> /// <returns>A location where this resource type is supported for the current subscription</returns> public static string GetResourceLocation(ResourceManagementClient client, string resourceType) { var supportedLocations = new HashSet<string>(new[] { "East US", "West US", "Central US", "West Europe" }, StringComparer.OrdinalIgnoreCase); string[] parts = resourceType.Split('/'); string providerName = parts[0]; var provider = client.Providers.Get(providerName); foreach (var resource in provider.Provider.ResourceTypes) { if (string.Equals(resource.Name, parts[1], StringComparison.OrdinalIgnoreCase)) { return resource.Locations.FirstOrDefault(supportedLocations.Contains); } } return null; }
static async Task MainAsync() { // Get the credentials SubscriptionCloudCredentials cloudCreds = GetCredsFromServicePrincipal(); // Create our own HttpClient so we can do logging HttpClient httpClient = new HttpClient(new LoggingHandler(new HttpClientHandler())); // Use the creds to create the clients we need _resourceGroupClient = new ResourceManagementClient(cloudCreds, httpClient); _websiteClient = new WebSiteManagementClient(cloudCreds, httpClient); await ListResourceGroupsAndSites(); // Note: site names are globally unique, so you may need to change it to avoid conflicts await CreateSite("MyResourceGroup", "MyWebHostingPlan", "SampleSiteFromAPI", "West US"); }
protected override bool CheckExistence() { if (Parameters.Properties.ResourceGroupExists) { using (var client = new ResourceManagementClient(GetCredentials())) { var result = client.Deployments.ListAsync(Parameters.Tenant.SiteName, new DeploymentListParameters() { ProvisioningState = ProvisioningState.Succeeded }).Result; return result.Deployments.Any(); } } return false; }
protected override bool CheckExistence() { if (Parameters.Properties.ResourceGroupExists) { using (var client = new ResourceManagementClient(GetCredentials())) { var result = client.Resources.ListAsync(new ResourceListParameters() { ResourceGroupName = Parameters.Tenant.SiteName, ResourceType = "Microsoft.DocumentDb/databaseAccounts" }).Result; return result.Resources.Any(r => r.Name.Equals(Parameters.Tenant.SiteName)); } } return false; }
public static Rm.IResourceManagementClient GetRealRmClient(ExampleSecrets secrets) { Rm.IResourceManagementClient client = null; if (secrets.Environment == "test") { string ArmTenant = secrets.TenantId; string ArmServicePrincipalIdentity = secrets.ClientId; string SubId = secrets.SubId; string Thumb = secrets.ClientSecret; // Use service principal with cert to authenticate against Azure X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); X509Certificate2 cert = store.Certificates.Find(X509FindType.FindByThumbprint, Thumb, false)[0]; ClientAssertionCertificate cac = new ClientAssertionCertificate(ArmServicePrincipalIdentity, cert); var context = new AuthenticationContext("https://login.windows-ppe.net/" + ArmTenant); AuthenticationResult result = context.AcquireTokenAsync("https://management.core.windows.net/", cac).Result; ServiceClientCredentials creds = new TokenCredentials(result.AccessToken); client = new Rm.ResourceManagementClient(creds) { SubscriptionId = secrets.SubId }; client.BaseUri = new Uri("https://api-dogfood.resources.windows-int.net/"); } else if (secrets.Environment == "dogfood") { string ArmTenant = secrets.TenantId; string ArmServicePrincipalIdentity = secrets.ClientId; string SubId = secrets.SubId; // Use service principal with cert to authenticate against Azure string secret = secrets.ClientSecret; var cac = new ClientCredential(ArmServicePrincipalIdentity, secret); var context = new AuthenticationContext("https://login.windows-ppe.net/" + ArmTenant); AuthenticationResult result = context.AcquireTokenAsync("https://management.core.windows.net/", cac).Result; ServiceClientCredentials creds = new TokenCredentials(result.AccessToken); client = new Rm.ResourceManagementClient(creds) { SubscriptionId = secrets.SubId }; client.BaseUri = new Uri("https://api-dogfood.resources.windows-int.net/"); } else if (secrets.Environment == "prod") { // Use Service Principal to authenticate against Azure var context = new AuthenticationContext("https://login.windows.net/" + secrets.TenantId); ClientCredential cc = new ClientCredential(secrets.ClientId, secrets.ClientSecret); AuthenticationResult result = context.AcquireTokenAsync("https://management.azure.com/", cc).Result; ServiceClientCredentials creds = new TokenCredentials(result.AccessToken); client = new Rm.ResourceManagementClient(creds) { SubscriptionId = secrets.SubId }; } else if (secrets.Environment == "nightly") { return(null); // Nightly environment is direct access to our RP, so no ARM } else { throw new ArgumentException("Secrets environment must be test, prod, or nightly, currently {0}", secrets.Environment); } return(client); }
static async Task MainAsync() { // Set Environment - Choose between Azure public cloud, china cloud and US govt. cloud _environment = AzureEnvironment.PublicEnvironments[EnvironmentName.AzureCloud]; // Get the credentials TokenCloudCredentials cloudCreds = GetCredsFromServicePrincipal(); var tokenCreds = new TokenCredentials(cloudCreds.Token); var loggingHandler = new LoggingHandler(new HttpClientHandler()); // Create our own HttpClient so we can do logging var httpClient = new HttpClient(loggingHandler); // Use the creds to create the clients we need _resourceGroupClient = new ResourceManagementClient(cloudCreds, _environment.GetEndpointAsUri(AzureEnvironment.Endpoint.ResourceManager), httpClient); _websiteClient = new WebSiteManagementClient(_environment.GetEndpointAsUri(AzureEnvironment.Endpoint.ResourceManager), tokenCreds, loggingHandler); _websiteClient.SubscriptionId = cloudCreds.SubscriptionId; await ListResourceGroupsAndSites(); // Note: site names are globally unique, so you may need to change it to avoid conflicts await CreateSite("MyResourceGroup", "MyAppServicePlan", "SampleSiteFromAPI", "West US"); // Upload certificate to resource group await UpdateLoadCertificate("MyResourceGroup", "CertificateName", "West US", "PathToPfxFile", "CertificatePassword"); }
public void Run() { // Try to obtain the authorization token var clientCredential = new ClientCredential(clientId, clientSecret); var context = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantId)); var result = context.AcquireTokenAsync("https://management.azure.com/", clientCredential).Result; if (result == null) { throw new InvalidOperationException("Failed to obtain authorization token"); } // Read the token and create the appropriate credentials object string token = result.AccessToken; var credentials = new TokenCredentials(token); // Read the template and parameter file contents JObject templateFileContents = GetJsonFileContents(pathToTemplateFile); JObject parameterFileContents = GetJsonFileContents(pathToParameterFile); // Create the resource manager client var resourceManagementClient = new ResourceManagementClient(credentials); resourceManagementClient.SubscriptionId = subscriptionId; // Create or check that resource group exists EnsureResourceGroupExists(resourceManagementClient, resourceGroupName, resourceGroupLocation); // Start a deployment DeployTemplate(resourceManagementClient, resourceGroupName, deploymentName, templateFileContents, parameterFileContents); }