Esempio n. 1
0
        private List <Models.AzureRegion> GetRegionsAvailableToPlan(string planId)
        {
            var db     = new CmpWapDb();
            var result = db.FetchAzureRegionListByPlan(planId);

            return(result);
        }
Esempio n. 2
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches os mapping to subscription information from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private bool GetRegionOSSubscriptionMappingValidationFromDb(int regionId, int osId)
        {
            var  cwdb   = new CmpWapDb();
            bool result = cwdb.GetRegionVmOSMappings(regionId, osId);

            return(result);
        }
Esempio n. 3
0
        //*********************************************************************
        ///
        ///  <summary>
        ///     This method is used to add disk to a VM.
        ///  </summary>
        ///  <param name="vMId"></param>
        /// <param name="disks"></param>
        ///
        //*********************************************************************
        private void AddDisk(int vMId, List <object> disks)
        {
            try
            {
                var cwdb = new CmpWapDb();
                var foundVmDepRequest = cwdb.FetchVmDepRequest(vMId);

                if (null != foundVmDepRequest)
                {
                    if (null != foundVmDepRequest.CmpRequestID)
                    {
                        if (!CanAddDisks((int)foundVmDepRequest.CmpRequestID, disks.Count))
                        {
                            throw new Exception("Role size of given VM does not support the requested number of data disks");
                        }

                        var cmpi = new VMServiceRepository(_eventLog);
                        cmpi.AddDisk(Convert.ToInt32(foundVmDepRequest.CmpRequestID), BuildDiskObject(disks, foundVmDepRequest).ToList());
                    }
                }
            }
            catch (Exception ex)
            {
                LogThis(ex, EventLogEntryType.Error, "CmpWapExtension.VmsController.AddDisk()", 100, 1);
                throw;
            }
        }
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches os mapping to subscription information from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private bool GetVmRegionSizeMappingValidationFromDb(int regionId, int sizeId)
        {
            var  cwdb   = new CmpWapDb();
            bool result = cwdb.GetRegionVmSizeMappings(regionId, sizeId);

            return(result);
        }
Esempio n. 5
0
        //*********************************************************************
        ///
        /// <summary>
        ///     Thie method returns a ScriptJob type
        /// </summary>
        /// <param name="wapSubscriptionId"></param>
        /// <param name="jobId"></param>
        /// <returns>ScriptJob</returns>
        ///
        //*********************************************************************

        public static ScriptJob GetScriptJob(string wapSubscriptionId, string jobId)
        {
            try
            {
                var cdb = new CmpWapDb();
                var sr  = cdb.FetchSequenceRequest(wapSubscriptionId, jobId);

                if (null == sr)
                {
                    if (null == wapSubscriptionId)
                    {
                        throw new Exception(string.Format("No record found for job '{0}' in any subscription", jobId));
                    }
                    else
                    {
                        throw new Exception(string.Format("No record found for job '{0}' in subscription '{1}' ", jobId,
                                                          wapSubscriptionId));
                    }
                }

                var ss = Convert(Convert(sr));

                CheckSequenceStatus(ss);
                return(Convert(ss));
            }
            catch (Exception ex)
            {
                throw new Exception("ScriptInterface.GetScriptJob() : " +
                                    Utilities.UnwindExceptionMessages(ex));
            }
        }
Esempio n. 6
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method is used to check whether a disk can be added to a VM
        /// </summary>
        /// <param name="cmpRequestId"></param>
        /// <param name="addDiskCount"></param>
        /// <returns>boolean</returns>
        ///
        //*********************************************************************

        private bool CanAddDisks(int cmpRequestId, int addDiskCount)
        {
            try
            {
                string roleSizeName;

                //*** Fetch disk count from Azure ***

                var cmpi  = new VMServiceRepository(_eventLog);
                var count = cmpi.FetchDiskCount(cmpRequestId, out roleSizeName);

                //*** fetch role size disc capacity info ***

                var cwdb         = new CmpWapDb();
                var roleSizeInfo = cwdb.FetchVmSizeInfo(roleSizeName);

                if (null == roleSizeInfo)
                {
                    throw new Exception(string.Format(
                                            "Could not locate given VM role size: '{0}' in server Role Size table", roleSizeName));
                }

                //*** Check capacity ***

                return(count + addDiskCount <= roleSizeInfo.MaxDataDiskCount);
            }
            catch (Exception ex)
            {
                LogThis(ex, EventLogEntryType.Error, "CmpWapExtension.VmsController.CanAddDisks()", 100, 1);
                throw;
            }
        }
Esempio n. 7
0
        //*********************************************************************
        ///
        /// <summary>
        /// Sync the CMP VM list with the CmpWap VM list
        /// </summary>
        ///
        //*********************************************************************

        public void SynchWithCmp()
        {
            var cmp  = new CmpApiClient(_eventLog);
            var cwdb = new CmpWapDb();

            //*** Fetch the CMP resource group list ***
            var cmpResGroupList = cmp.FetchAzureResourceGroups();

            //*** Fetch the CmpWap app list ***
            var cmpWapAppList = cwdb.FetchAppList();

            //*** Fold ***
            foreach (var cmpResGroup in cmpResGroupList.Where(cmpResGroup =>
                                                              !cmpWapAppList.Any(cmpWapApp => cmpResGroup.Name.Equals(
                                                                                     cmpWapApp.Name, StringComparison.InvariantCultureIgnoreCase))))
            {
                ImportApp(cmpResGroup, cwdb);
            }

            //*** Fetch the CMP VM list ***
            var cmpVmList = cmp.FetchCmpRequests();

            //*** Fetch the CmpWap VM list ***
            var cmpWapVmList = cwdb.FetchVmDepRequests(null, true);

            //*** Fold ***
            foreach (var cmpVm in cmpVmList.Where(cmpVm =>
                                                  !cmpWapVmList.Any(cmpWapVm => cmpVm.TargetVmName.Equals(
                                                                        cmpWapVm.TargetVmName, StringComparison.InvariantCultureIgnoreCase))))
            {
                ImportVm(cmpVm, cwdb);
            }
        }
Esempio n. 8
0
        //*********************************************************************
        ///
        /// <summary>
        ///
        /// </summary>
        /// <param name="resGroup"></param>
        /// <param name="cwdb"></param>
        ///
        //*********************************************************************

        private void ImportApp(CmpServiceLib.Models.Container resGroup, CmpWapDb cwdb)
        {
            try
            {
                var app = new Application()
                {
                    ApplicationId  = 0,
                    Code           = resGroup.Code,
                    Name           = resGroup.Name,
                    HasService     = (bool)resGroup.HasService,
                    IsActive       = resGroup.IsActive,
                    SubscriptionId = resGroup.SubscriptionId,
                    CreatedOn      = resGroup.CreatedOn,
                    CreatedBy      = resGroup.CreatedBy,
                    LastUpdatedOn  = resGroup.LastUpdatedOn,
                    LastUpdatedBy  = resGroup.LastUpdatedBy,
                    CIOwner        = resGroup.CIOwner,
                    Region         = resGroup.Region
                };

                cwdb.InsertApp(app);
            }
            catch (Exception ex)
            {
                LogThis(ex, EventLogEntryType.Error,
                        "Exception in SyncWorker.ImportApp()", 0, 0);
            }
        }
Esempio n. 9
0
        private static void UpdateAzureRegions(IEnumerable <AzureCatalogue> azureCatalogueResult)
        {
            try
            {
                var cmpWapDb     = new CmpWapDb();
                var cmpRegions   = cmpWapDb.FetchAzureRegionList(onlyActiveOnes: false);
                var azureRegions = azureCatalogueResult.Select(ac => new AzureRegion
                {
                    Name             = ac.RegionName,
                    Description      = ac.RegionDisplayName,
                    OsImageContainer = null,
                    IsActive         = true,
                    CreatedBy        = "CMP WAP Extension",
                    LastUpdatedBy    = "CMP WAP Extension",
                    CreatedOn        = DateTime.UtcNow,
                    LastUpdatedOn    = DateTime.UtcNow
                });

                var newRegions = azureRegions.Where(azureItem => !cmpRegions.Any(cmpItem => string.Equals(azureItem.Name.Replace(" ", string.Empty), cmpItem.Name.Replace(" ", string.Empty), StringComparison.InvariantCultureIgnoreCase))).ToList();

                if (newRegions.Any())
                {
                    cmpWapDb.InsertAzureRegionByBatch(newRegions);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Exception caught in UpdateAzureRegions: " + ex.ToString());
            }
        }
Esempio n. 10
0
        public VmDashboardInfo GetVm(string subscriptionId, int Id)
        {
            try
            {
                ICmpWapDb cwdb = new CmpWapDb();
                ICmpWapDbTenantRepository cwdbTenant = new CmpWapDb();

                var foundVmDepRequest = cwdb.FetchVmDepRequest(Id);
                var vmsizes           = cwdbTenant.FetchVmSizeInfoList(subscriptionId);
                if (null != foundVmDepRequest && null != foundVmDepRequest.CmpRequestID)
                {
                    var cmpi = new VMServiceRepository(_eventLog);

                    //when we solve the big 'method not returning' bug: uncomment line below, delete second line below
                    //var vm = cmpi.GetVm(Convert.ToInt32(foundVmDepRequest.CmpRequestID),
                    //    CmpInterfaceModel.Constants.FetchType.AzureStatus);
                    var vm = GetLocalvmDBI(foundVmDepRequest);
                    cwdb.UpdateVmIp(Id, vm.InternalIP);
                    vm.Cores = vmsizes.Where(x => x.Name == vm.RoleSize).Select(x => x.Cores).FirstOrDefault().ToString();
                    vm.OSVirtualHardDisk.Type = "OS Disk";
                    if (vm.DataVirtualHardDisks != null)
                    {
                        vm.DataVirtualHardDisks.Select(d => { d.Type = "Data Disk"; return(d); }).ToList();
                    }
                    return(vm);
                }
                return(null);
            }
            catch (Exception ex)
            {
                LogThis(ex, EventLogEntryType.Error, "CmpWapExtension.VmsController.GetVm()", 100, 1);
                throw;
            }
        }
Esempio n. 11
0
        //*********************************************************************
        ///
        /// <summary>
        ///     Fetch list of applications from WAP DB
        /// </summary>
        ///
        //*********************************************************************

        private void FetchAppListFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchAppList();

            appList.Clear();
            appList.AddRange(list);
        }
Esempio n. 12
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches IIS RoleService from the WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchIISRoleServiceFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchIisRoleServiceInfoList();

            appList.Clear();
            appList.AddRange(list);
        }
Esempio n. 13
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method is used to fetch SQL version infromation from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchSQLVersionFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchSqlVersionInfoList();

            VersionList.Clear();
            VersionList.AddRange(list);
        }
Esempio n. 14
0
        //*********************************************************************
        ///
        /// <summary>
        /// This method fetches srever role information from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchServerRoleFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchServerRoleInfoList();

            RoleList.Clear();
            RoleList.AddRange(list);
        }
Esempio n. 15
0
        //*********************************************************************
        ///
        /// <summary>
        /// This method fetches network NICs from WAP DB
        /// </summary>
        ///
        //*********************************************************************

        private void FetchNetworkNICFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchNetworkNicInfoList();

            nicList.Clear();
            nicList.AddRange(list);
        }
Esempio n. 16
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method is used to fetch SQL collation information from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchSQLCollationFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchSqlCollationInfoList();

            Collations.Clear();
            Collations.AddRange(list);
        }
Esempio n. 17
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches drive mapping infomration from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchServerRoleDriveMappingsFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchServerRoleDriveInfoList();

            DriveMappingList.Clear();
            DriveMappingList.AddRange(list);
        }
        //*********************************************************************
        ///
        /// <summary>
        ///     This methid fetches environment types from WAP DB
        /// </summary>
        ///
        //*********************************************************************

        private void FetchEnvironmentTypeFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchEnvironmentTypeInfoList();

            roleList.Clear();
            roleList.AddRange(list);
        }
Esempio n. 19
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetchs Azure region specific information from the
        ///     WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchAzureRegionFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchAzureRegionList(onlyActiveOnes: true);

            OsList.Clear();
            OsList.AddRange(list);
        }
Esempio n. 20
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches VM size information from WAP DB.
        /// </summary>
        ///
        /// All Azure sizes -> https://msdn.microsoft.com/en-us/library/azure/dn197896.aspx
        ///
        //*********************************************************************

        private void FetchVmSizeFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchVmSizeInfoList(onlyActiveOnes: true);

            SizeList.Clear();
            SizeList.AddRange(list);
        }
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches service category related information from
        ///     WAp DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchServiceCategoriesFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchServiceCategoryInfoList();

            ServiceCategoryList.Clear();
            ServiceCategoryList.AddRange(list);
        }
Esempio n. 22
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method is used to fetch SQL Server Analysis services modes
        ///     from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchSQLAnalysisServicesModeFromDb()
        {
            var cwdb = new CmpWapDb();
            var list = cwdb.FetchSqlAnalysisServicesModeInfoList();

            AppList.Clear();
            AppList.AddRange(list);
        }
Esempio n. 23
0
        private static void UpdateVmSizes(IEnumerable <AzureCatalogue> azureCatalogueResult)
        {
            try
            {
                var cmpWapDb              = new CmpWapDb();
                var cmpWapVmSizes         = cmpWapDb.FetchVmSizeInfoList(onlyActiveOnes: false).ToList();
                var newVmSizes            = new List <VmSize>();
                var azureCatalogueVmSizes = new List <AzureVmSizeArmData>();

                //Eliminate dupes, we only need them to establish the mappings in another method.
                foreach (var regionInCatalogue in azureCatalogueResult)
                {
                    azureCatalogueVmSizes.AddRange(regionInCatalogue.VmSizes);
                }
                azureCatalogueVmSizes = azureCatalogueVmSizes.Distinct(new AzureVmSizeArmData.AzureVmSizeComparer()).ToList();

                //Translate and convert each AzureVmSizeArmData object into a VmSize object.
                foreach (var vmSize in azureCatalogueVmSizes)
                {
                    if (!cmpWapVmSizes.Any(x => string.Equals(vmSize.name, x.Name, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        var newVmSize = new VmSize
                        {
                            Name             = vmSize.name,
                            Cores            = vmSize.numberOfCores,
                            Memory           = vmSize.memoryInMB,
                            MaxDataDiskCount = vmSize.maxDataDiskCount,
                            IsActive         = true,
                            CreatedBy        = "CMP WAP Extension",
                            LastUpdatedBy    = "CMP WAP Extension",
                            CreatedOn        = DateTime.UtcNow,
                            LastUpdatedOn    = DateTime.UtcNow
                        };

                        if (vmSize.memoryInMB >= 1000)
                        {
                            newVmSize.Description = vmSize.name + " - " + vmSize.numberOfCores + " Cores, " + vmSize.memoryInMB / 1000 + " GB, " + vmSize.maxDataDiskCount + " Disk";
                        }
                        else
                        {
                            newVmSize.Description = vmSize.name + " - " + vmSize.numberOfCores + " Cores, " + vmSize.memoryInMB + " MB, " + vmSize.maxDataDiskCount + " Disk";
                        }

                        newVmSizes.Add(newVmSize);
                    }
                }


                if (newVmSizes.Any())
                {
                    cmpWapDb.InsertVmSizeByBatch(newVmSizes);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Exception caught in UpdateVmSizes: " + ex.ToString());
            }
        }
Esempio n. 24
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method returns a ScriptJob type
        /// </summary>
        /// <param name="scriptJob"></param>
        /// <param name="wapSubscriptionId"></param>
        /// <returns>ScriptJob</returns>
        ///
        //*********************************************************************

        public static ScriptJob SubmitScriptJob(ScriptJob scriptJob,
                                                string wapSubscriptionId)
        {
            if (scriptJob == null)
            {
                throw new ArgumentNullException("scriptJob");
            }

            if (wapSubscriptionId == null)
            {
                throw new ArgumentNullException("wapSubscriptionId");
            }

            try
            {
                var seqSpec = Convert(scriptJob);
                seqSpec = CmpClient.CmpScriptClient.ExecuteSmaScript(seqSpec);

                var sequenceRequest = new SequenceRequest
                {
                    Active           = true,
                    CmpRequestID     = 0,
                    Config           = seqSpec.Serialize(),
                    ExceptionMessage = null,
                    Id = 0,
                    LastStatusUpdate        = seqSpec.RunResult.LastUpdate,
                    ServiceProviderJobId    = seqSpec.RunResult.JobId,
                    ServiceProviderName     = seqSpec.SmaConfig.SmaServerUrl,
                    ServiceProviderTypeCode = seqSpec.Engine,
                    StatusCode        = seqSpec.RunResult.StatusCode,
                    StatusMessage     = seqSpec.RunResult.StatusMessage,
                    TagData           = seqSpec.TagData,
                    TagID             = 0,
                    TagOpName         = seqSpec.SmaConfig.RunbookName,
                    TargetName        = scriptJob.TargetName,
                    TargetTypeCode    = scriptJob.TargetTypeCode,
                    WapSubscriptionID = wapSubscriptionId,
                    Warnings          = null,
                    WhenRequested     = seqSpec.RunResult.WhenSubmitted,
                    WhoRequested      = null
                };

                var cdb = new CmpWapDb();
                sequenceRequest = cdb.InsertSequenceRequest(sequenceRequest);
                seqSpec.ID      = sequenceRequest.Id;

                return(Convert(seqSpec));
            }
            catch (Exception ex)
            {
                throw new Exception("ScriptInterface.SubmitScriptJob() : " +
                                    Utilities.UnwindExceptionMessages(ex));
            }
        }
Esempio n. 25
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches VM size information from WAP DB for the corresponding subscriptionid.
        /// </summary>
        ///
        /// All Azure sizes -> https://msdn.microsoft.com/en-us/library/azure/dn197896.aspx
        ///
        //*********************************************************************

        private void FetchVmSizeFromDb(string subscriptionId)
        {
            var cwdb = new CmpWapDb();

            if (!string.IsNullOrEmpty(subscriptionId))
            {
                var repository = cwdb as ICmpWapDbTenantRepository;
                var list       = repository.FetchVmSizeInfoList(subscriptionId);
                SizeList.Clear();
                SizeList.AddRange(list);
            }
        }
Esempio n. 26
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method fetches domain list from WAP DB
        /// </summary>
        ///
        //*********************************************************************

        private void FetchVmListFromDb()
        {
            var cwdb       = new CmpWapDb();
            var domainList = cwdb.FetchDomainInfoList();

            _havePendingStatus = false;
            DomainList.Clear();

            foreach (var dom in domainList)
            {
                AddVmToList(dom);
            }
        }
Esempio n. 27
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method returns a list of ScriptJob type
        /// </summary>
        /// <param name="wapSubscriptionId"></param>
        /// <returns>list of ScriptJob</returns>
        ///
        //*********************************************************************

        public static List <ScriptJob> GetScriptJobList(string wapSubscriptionId)
        {
            try
            {
                var cdb = new CmpWapDb();
                return(Convert(cdb.FetchSequenceRequests(wapSubscriptionId)));
            }
            catch (Exception ex)
            {
                throw new Exception("ScriptInterface.GetScriptJobList() : " +
                                    Utilities.UnwindExceptionMessages(ex));
            }
        }
Esempio n. 28
0
        //*********************************************************************
        ///
        ///  <summary>
        ///     This method is used to convert VMOp type in OpSpec type
        ///  </summary>
        /// <param name="vmOp"></param>
        ///
        //*********************************************************************

        public static OpSpec Translate(VmOp vmOp)
        {
            var cwdb = new CmpWapDb();
            var foundVmDepRequest = cwdb.FetchVmDepRequest(vmOp.VmId);

            if (null == foundVmDepRequest)
            {
                throw new Exception("VM not found in DB");
            }

            if (null == foundVmDepRequest.CmpRequestID)
            {
                throw new Exception("CmpRequestID not found for given VM");
            }

            if (vmOp.Name == null)
            {
                vmOp.Name = string.Format("{0} : {1}", vmOp.Opcode, foundVmDepRequest.TargetVmName);
            }

            List <CmpCommon.VhdInfo> diskList = null;

            if (vmOp.disks != null)
            {
                diskList = BuildDiskObject(vmOp.disks, foundVmDepRequest).ToList();
            }

            if (!String.IsNullOrEmpty(foundVmDepRequest.Domain))
            {
                vmOp.Name += "." + foundVmDepRequest.Domain;
                foundVmDepRequest.TargetVmName += "." + foundVmDepRequest.Domain;
            }

            return(new OpSpec()
            {
                Config = vmOp.Config,
                Disks = diskList,
                Id = vmOp.Id,
                Name = vmOp.Name,
                Opcode = vmOp.Opcode,
                StatusCode = vmOp.StatusCode,
                StatusMessage = vmOp.StatusMessage,
                TargetId = (int)foundVmDepRequest.CmpRequestID,
                TargetName = foundVmDepRequest.TargetVmName,
                TargetType = "VM",
                Vmsize = vmOp.Vmsize,
                iData = vmOp.iData,
                sData = vmOp.sData
            });
        }
Esempio n. 29
0
        //*********************************************************************
        ///
        /// <summary>
        ///     This method is used to fetch VM list from WAP DB.
        /// </summary>
        ///
        //*********************************************************************

        private void FetchVmListFromDb()
        {
            var cwdb       = new CmpWapDb();
            var cmpReqList = cwdb.FetchVmDepRequests(null, true);

            _havePendingStatus = false;
            VmList.Clear();

            foreach (Models.CmpRequest cmpReq in cmpReqList)
            {
                AddVmToList(cmpReq);
            }

            SyncWithCmp();
        }
Esempio n. 30
0
 private void DeleteWapdbRecord(int id, CmpWapDb cwdb = null)
 {
     try
     {
         if (cwdb == null)
         {
             cwdb = new CmpWapDb();
         }
         cwdb.DeleteVmDepRequest(id);
         RemoveVmFromList(id);
     }
     catch (Exception ex)
     {
         throw new Exception(ex.Message);
     }
 }