Is there a way, in a 'switch' to modify the variable you are evaluating on, and get it to change the match?
$var = "a"
switch ($var){
"a" {Write-Host "1st match for 'a'"}
"b" {Write-Host "1st match for 'b'"}
"a" {Write-Host "2nd match for 'a'"; $var = "b" ; continue}
"b" {Write-Host "2st match for 'b'"}
}
I would love to be able to get the above to match:
1st match for 'a'
2nd match for 'a'
2nd match for 'b'
$Destination = "vmstores:\vcsa#443\Training\Local-B\David" #is a param of my function, which could be a bunch of different types of object.
$DestinationType = $Destination.GetType().Name
switch ($DestinationType){
"String" {
if ((Test-Path $Destination) -eq $true){
if ((Get-Item $Destination).GetType().Name -eq "DatastoreFolderImpl"){
$DestinationType = "DatastoreFolderImpl"
if ((Test-Path $Destination.Insert($Destination.Length,"\").Insert(($Destination.Length)+1,$SourceVMXShort)) -eq $true){
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
}
elseif ((Get-Item $Destination).GetType().Name -eq "DatastoreFileImpl"){
$DestinationType = "DatastoreFileImpl"
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
}
; continue
}
"DirectoryInfo" {
if ((Test-Path $Destination.Insert($Destination.Length,"\").Insert(($Destination.Length)+1,$SourceVMXShort)) -eq $true){
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
; break
}
"FileInfo" {
if ((Test-Path $Destination) -eq $true){
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
; break
}
"DatastoreFileImpl" {
if ((Test-Path $Destination) -eq $true){
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
; break
}
"DatastoreFolderImpl" {
if ((Test-Path $Destination.Insert($Destination.Length,"\").Insert(($Destination.Length)+1,$SourceVMXShort)) -eq $true){
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
; break
}
"NasDatastoreImpl" {
New-PSDrive -Name "DestMount" -Root \ -PSProvider VimDatastore -Datastore $Destination | Out-Null
if ((Test-Path ("DestMount:").insert(10,"\").Insert(11,$SourceVMXShort)) -eq $true){
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
$Destination = ("DestMount:").insert(10,"\")
; break
}
"VMFSDatastoreImpl" {
New-PSDrive -Name "DestMount" -Root \ -PSProvider VimDatastore -Datastore $Destination | Out-Null
if ((Test-Path ("DestMount:").insert(10,"\").Insert(11,$SourceVMXShort)) -eq $true){
Write-Warning "Destination File exists..."
$DestinationExists = $true
}
$Destination = ("DestMount:").insert(10,"\")
; break
}
}
As you can see, it would be more elegant if i could update the $DestinationType so i could re-use the statement in the other switch blocks, rather than the extra 'ifs'
While I don't think you can change the switch statements variable mid check, you can do nested switch statements. This code gives your requested output:
$var = "a"
switch ($var){
"a" {Write-Host "1st match for 'a'"}
"b" {Write-Host "1st match for 'b'"}
"a" {Write-Host "2nd match for 'a'"
$var = "b"
switch ($var) {
"b" {Write-Host "2st match for 'b'"}
} #End sub-switch
} #End "A" check
} #End Primary switch
Now, I'm not sure what your overall goal is, there might be better ways to do this with functions and such.
Edit after updated question and comments:
From looking at the updated code, you can pull the one if statement that sets $DestinationExists = $true. You might be able to reorganize your if statements so they only show up once. Unfortunately, there is no way to get the switch statement to change the variable mid-switch. From your comment, maybe you can add an extra parameter that will dictate the type, so you can us one large switch statement based off the type. Something like this:
switch ($DataType) {
"String" {<#Things to do if string#>}
"OtherTypes" {<#Continue like this#>}
}#End Switch ($DataType)
I think at that point though, I would start using Parameter Sets. Here is a blog describing about Parameter Sets
Here is a somewhat convoluted way to do it. Note that the example code is similar but not the same as the code in OP.
add-type #"
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
public class PSVarEnumeration : IEnumerable
{
private ScriptBlock _getterScript;
public PSVarEnumeration(ScriptBlock getterScript)
{
_getterScript = getterScript;
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator) GetEnumerator();
}
public PSVarEnumerator GetEnumerator()
{
return new PSVarEnumerator(_getterScript);
}
}
public class PSVarEnumerator : IEnumerator
{
private ScriptBlock _getterScript;
bool areDone = false;
// position isn't used for anything
int position = -1;
public PSVarEnumerator(ScriptBlock getterScript)
{
_getterScript = getterScript;
}
public bool MoveNext()
{
if (!areDone) {
if (Current != null) {
position++;
return true;
} else {
areDone = true;
return false;
}
} else {
return false;
}
}
public void Reset()
{
position = -1;
areDone = false;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public Object Current
{
get
{
Collection<PSObject> results = _getterScript.Invoke();
return results[0];
}
}
}
"#
$mySwitcher ="a"
$mySwitcherScript = {$mySwitcher}
$var = new PSVarEnumeration ( $mySwitcherScript)
switch ($var){
"a" {Write-Host "1st match for 'a'"}
"b" {Write-Host "1st match for 'b'"}
"a" {Write-Host "2nd match for 'a'"; $mySwitcher = "b" ; continue}
"b" {Write-Host "2nd match for 'b'"; $mySwitcher = $null}
}
<#
Output I get is:
1st match for 'a'
2nd match for 'a'
1st match for 'b'
2nd match for 'b'
#>
Related
I'm newbie with powershell. I am always learning about, and I started last Friday. So forgive me if it's obvious!
I don't why the first if statement pass whereas the condition is not respected.
I'm trying to check if a program is running on my computer. If yes, it's telling me "Programme is running" ! And when it's not running anymore, it write that is not running.
There is my code :
if (isPrgmRunning -eq $true) {
isPrgmRunning #Return false, why the last if statement pass ???
write-output "Programme is running"
$isRunning = $true
while($isRunning) {
write-output "While the programme keep running"
if(CheckInternetConnection) {
if(isPrgmRunning -eq $false) {
isPrgmRunning #Check again value, and it's false
Write-Output "If it's not running anymore"
$isRunning = $false
}
}
}
}
I don't understand why it's not running and the first if pass...
There is all the scrpit :
$global:previousStatus=$null
# Function to check if the computer is connected to the internet
Function CheckInternetConnection {
$currentStatus = Test-Connection -ComputerName "www.google.com" -Count 1 -Quiet
If ($currentStatus -ne $global:previousStatus) {
If ($currentStatus) {
ShowMessageBox "Connected"
}
Else {
ShowMessageBox "Disconnected"
}
$global:previousStatus = $currentStatus
}
return $currentStatus
}
# Function to display a message box
Function ShowMessageBox {
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[System.Windows.Forms.MessageBox]::Show($args[0], "Internet Connection Status")
}
# Function to check if the "Minecraft" program is running can be replace by any other
Function isPrgmRunning {
try {
$process = Get-Process -Name "Minecraft" -ErrorAction Stop #This is an exemple of programme :)
if ($process -ne $null) {
write-output "Prgm run"
return $true
}
} catch [Microsoft.PowerShell.Commands.ProcessCommandException] {
write-output "Prgm not run"
return $false
}
}
# Main function
function Main {
while($true){
if (CheckInternetConnection) {
write-output "Connected"
if (isPrgmRunning -eq $true) {
isPrgmRunning #Return false, why the last if statement pass ???
write-output "Programme is running"
$isRunning = $true
while($isRunning) {
write-output "While the programme keep running"
if(CheckInternetConnection) {
if(isPrgmRunning -eq $false) {
isPrgmRunning #Check again value, and it's false
Write-Output "If it's not running anymore"
$isRunning = $false
}
}
}
}
}
Start-Sleep -Seconds 1
}
}
Main
Thank you for any help on my script ! I'll hear all advice and solution that you can send me !
[Edit]: Problem solved. It was on isPrgmRunning. I don't know why but instead of this :
$process = Get-Process -Name "Minecraft" -ErrorAction Stop
I've take this on educba.com/powershell-boolean/ :
Get-Process | where{$_.Name -eq "Wrong process"} -ErrorAction Ignore
So we get this :
Function isPrgmRunning {
$process = Get-Process | where{$_.Name -eq "Minecraft"} -ErrorAction Ignore #Still with Minecraft but it can be "Teams" or something else
if($process){
return $true
}
else{
return $false
}
}
Evaluate the function, at the moment you're just checking if it exists, Try it this way:
$checkinternetconnection = $true
Function isPrgmRunning {
try {
$process = Get-Process -Name "Teams" -ErrorAction Stop #This is an exemple of programme :)
if ($process -ne $null) {
write-output "Prgm run"
return $true
}
} catch [Microsoft.PowerShell.Commands.ProcessCommandException] {
write-output "Prgm not run"
return $false
}
}
function Main {
while($true){
if ($CheckInternetConnection) {
write-output "Connected"
if (isPrgmRunning) {
isPrgmRunning #Return false, why the last if statement pass ???
write-output "Programme is running"
$isRunning = $true
while($isRunning) {
write-output "While the programme keep running"
if($CheckInternetConnection) {
if(!(isPrgmRunning)) {
isPrgmRunning #Check again value, and it's false
Write-Output "If it's not running anymore"
$isRunning = $false
}
}
}
}
}
Start-Sleep -Seconds 1
}
}
main
I am getting my feet wet with PS classes, by trying to implement a path type identifier class. Basically I want to pass a string in and identify variations on file system and registry paths. Mostly it is working, but oddly the first item I test, no matter what it is, the properties are blank when I look, though no error shows up. And it seems like the results are actually from the previous instance, at least for the "successful" instances. Thrown exceptions seem to be working as expected. So, when $test = #('C:\folder', 'D:\', 'C:', 'K:', '\\Server\Folder\*', '\junk', '?:'), my results will be
C:\folder
D:\
FileSystem_Folder
LocalDisk folder
C:
FileSystem_Drive
OpticalDisk drive
K:
FileSystem_Drive
LocalDisk drive
\\Server\Folder\*
FileSystem_Drive
Unknown drive
! \junk
Not Identified: \junk
! ?:
Not Identified: ?:
This is the code in question.
class PxPath {
# Properties
hidden [array]$validPathTypes = #('FileSystem_Drive', 'FileSystem_Folder', 'FileSystem_File', 'Registry_Key', 'Registry_Property')
hidden [hashtable]$regExLookup = #{
registryHive = '^(?<hive>HKCC|HKEY_CURRENT_CONFIG|HKCR|HKEY_CLASSES_ROOT|HKCU|HKEY_CURRENT_USER|HKLM|HKEY_LOCAL_MACHINE)(?<seperator>:)?$'
registryPath = '^(?<hive>HKCC|HKEY_CURRENT_CONFIG|HKCR|HKEY_CLASSES_ROOT|HKCU|HKEY_CURRENT_USER|HKLM|HKEY_LOCAL_MACHINE)(?<seperator>:)?\\(?<remainder>.+)$'
fileSystemDriveOnly= '^(?<drive>[a-zA-Z]:)(\\)?$'
fileSystemDrivePath = '^(?<drive>[a-zA-Z]:)\\(?<remainder>.+)$'
fileSystemUNCPath = '^(?<server>\\\\[^<>:"/\\\|]*)\\(?<remainder>.+)$'
}
hidden [hashtable]$driveTypeLookup = #{
0 = 'Unknown'
1 = 'NoRootDirectory'
2 = 'RemovableDisk'
3 = 'LocalDisk'
4 = 'NetworkDrive'
5 = 'OpticalDisk'
6 = 'RamDisk'
}
[string]$Description = $null
[string]$Type = $null
# Constructors
PxPath ([string]$path) {
$this.PathType($path)
}
PxPath ([string]$path, [string]$pathType) {
if ($this.validPathTypes -contains $pathType) {
$this.PathType($path)
if ($this.Type -ne $pathType) {
Throw "$($this.Type) does not match: $pathType"
}
} else {
Throw "Not a valid path type: $pathType"
}
}
hidden [void] PathType ([string]$path) {
[string]$driveType = $null
[string]$extension = $null
[string]$extension = $null
switch -regex ($path) {
$this.regExLookup.fileSystemDriveOnly {
$driveType = $this.driveTypeLookup.Get_Item([int](Get-WmiObject Win32_LogicalDisk -computerName:. -filter:"name='$($matches.drive)'" | Select DriveType).DriveType)
$this.Description = "$driveType drive"
$this.Type = 'FileSystem_Drive'
}
$this.regExLookup.fileSystemDrivePath {
$driveType = $this.driveTypeLookup.Get_Item([int](Get-WmiObject Win32_LogicalDisk -computerName:. -filter:"name='$($matches.drive)'" | Select DriveType).DriveType)
if ($extension = [System.IO.Path]::GetExtension($path)) {
$this.Description = "$driveType file"
$this.Type = 'FileSystem_File'
} else {
$this.Description = "$driveType folder"
$this.Type = 'FileSystem_Folder'
}
}
$this.regExLookup.fileSystemUNCPath {
if ($extension = [System.IO.Path]::GetExtension($path)) {
$this.Description = "UNC file"
$this.Type = 'FileSystem_File'
} else {
$this.Description = "UNC folder"
$this.Type = 'FileSystem_Folder'
}
}
$this.regExLookup.registryPath {
}
default {
Throw "Not Identified: $path"
}
}
}
}
CLS
$test = #('C:\folder', 'D:\', 'C:', 'K:', '\\Server\Folder\*', '\junk', '?:')
foreach ($testitem in $test) {
$path = try {
[PxPath]::New($testitem)
Write-Host $testitem
Write-Host " $($path.Type)"
Write-Host " $($path.Description)"
Write-Host
} catch {
Write-Host "! $testitem"
Write-Host " $($_.Exception.Message)"
Write-Host
}
}
I suspect the issue is something I just don't understand with classes, but I guess a bug in PowerShell that I need to work around could also be the culprit.
I am attempting to mock up a data structure and logic to handle deferred log writing, and I am running into an odd situation. if ([collections.arrayList]$deferredLog = Get-PxDeferredLogItems) { errors when the returned arrayList is only one item, with
Cannot convert the "logged: 07/20/2019 10:56:29" value of type "System.String" to type "System.Collections.ArrayList".
Once there are two items it's fine. Now I know an array of a single item needs to be forced to be an array because PS is sometimes too clever for it's own good, but I thought the Add method of a [collections.arrayList] produced an arrayList even on the first Add. AM I totally misunderstanding, or is my logic wrong somewhere else?
I also tried casting the results of the function call like this
if ([collections.arrayList]$deferredLog = [collections.arrayList](Get-PxDeferredLogItems)) { but that is even worse, it errors at every call. I also tried initializing the variable to an empty arrayList with Set-PxDeferredLogItems (New-Object collections.arrayList) in Main, rather the n initializing it on the first call of Add-PxDeferredLogItem, but that shows the same behavior, errors until the deferred log has two items. I verified this by changing the Write-Host directly after the erroring line to Write-Host "Process deferred items $($deferredLog.count)", and I get errors till it shows a 2, then everything works as expected.
function Get-PxDeferredLogItems {
return $script:deferredLogItems
}
function Set-PxDeferredLogItems {
param (
[collections.arrayList]$deferredLog
)
[collections.arrayList]$script:deferredLogItems = $deferredLog
}
function Add-PxDeferredLogItem {
param (
[string]$item
)
if (-not $script:deferredLogItems) {
[collections.arrayList]$script:deferredLogItems = New-Object collections.arrayList
}
[void]$script:deferredLogItems.Add($item)
}
function Add-PxLogContent {
param (
[string]$string
)
function Assert-PxWrite {
if ((Get-Random -minimum:1 -maximum:4) -gt 1) {
return $true
} else {
return $false
}
}
if ([collections.arrayList]$deferredLog = Get-PxDeferredLogItems) {
Write-Host "Process deferred items"
:deferredItemsWrite do {
if (Assert-PxWrite) {
Write-Host "$($deferredLog[0]) ($(Get-Date))"
$deferredLog.RemoveAt(0)
} else {
break :deferredItemsWrite
}
} while ($deferredLog.count -gt 0)
if ($deferredLog.count -eq 0) {
$deferredLogPending = $false
} else {
$deferredLogPending = $true
}
Set-PxDeferredLogItems $deferredLog
} else {
$deferredLogPending = $false
}
if (-not $deferredLogPending) {
if (Assert-PxWrite) {
Write-Host $string
} else {
Add-PxDeferredLogItem $string
}
} else {
Add-PxDeferredLogItem $string
}
}
### MAIN
$startTime = Get-Date
$endTime = $startTime + (New-TimeSpan -minutes:2)
Clear-Host
do {
Add-PxLogContent "logged: $(Get-Date)"
Start-SLeep -s:5
} while ((Get-Date) -lt $endTime)
if ($deferredLog = Get-PxDeferredLogItems) {
foreach ($item in $deferredLog) {
Write-Host "!$item"
}
}
EDIT: It seems to be related to passing the arrayList, as this works as expected when there are no functions involved.
Clear-Host
$deferredLogItems = New-Object collections.arrayList
Write-Host "$($deferredLogItems.getType()) $($deferredLogItems.count) $deferredLogItems"
[void]$deferredLogItems.Add('One')
Write-Host "$($deferredLogItems.getType()) $($deferredLogItems.count) $deferredLogItems"
[void]$deferredLogItems.Add('Two')
Write-Host "$($deferredLogItems.getType()) $($deferredLogItems.count) $deferredLogItems"
[void]$deferredLogItems.Add('Three')
Write-Host "$($deferredLogItems.getType()) $($deferredLogItems.count) $deferredLogItems"
function Get-DeferredLogItems {
if (-not $script:deferredLogItems) {
[collections.arrayList]$script:deferredLogItems = New-Object collections.arrayList
}
[void]$script:deferredLogItems.Add("$($script:deferredLogItems.count + 1)")
return $script:deferredLogItems
}
$script:deferredLogItems = $localDeferredLogItems = $null
foreach ($i in 1..5) {
[collections.arrayList]$localDeferredLogItems = Get-DeferredLogItems
Write-Host "$($localDeferredLogItems.getType()) $($localDeferredLogItems.count) $localDeferredLogItems"
}
EDIT2: Replaced the line # reference with the actual offending line of code, because Confusion.
EDIT3: For what it's worth, forcing the results of Get-DeferredLogItems into an array DOES work. But I still wonder why that's even needed. Why does the Add method produce a correct arrayList at first add but this gets #%#$ed up by PowerShell when passed as a return value?
$mbservers = #("server1", "server2")
Foreach ($mbserver in $mbservers) {
#Check for reg key
Invoke-Command -Computername $mbserver -Credential $credsschedtask -ScriptBlock {
$regkey = "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\DisableLoopbackCheck"
$checkregkey = (Test-Path $regkey)
If ($checkregkey = "True") {
Write-Host "'DisableLoopbackCheck' key exists on $mbserver".
}
ElseIf ($checkregkey = "False") {
Write-Host "'DisableLoopbackCheck' key does not exist on $mbserver."
}
Else {
Write-Host "Unable to confirm if 'DisableLoopbackCheck' key exists on $mbserver."
}
}
}
I'm trying to workout the Write-Host variable so it display's server1 etc
(Write-Host "'DisableLoopbackCheck' key exists on $mbserver".)
Have tried the following in various ways:
For($i=0; $i -le $mbservers.getupperBound(0);$i++){
write-host $mbservers[$i]
write-host "line 2 :," $mbservers[$i]
I would be grateful for any help.
Your If and ElseIf comparisons don't function at the moment:
= is used for setting values, -eq is used for comparing them
Test-Path doesn't return a string "True", it returns a bool $True
As a bool only has two states $True or $False, you only need If/Else:
Foreach ($mbserver in $mbservers) {
#Check for reg key
Invoke-Command -Computername $mbserver -Credential $credsschedtask -ScriptBlock {
$checkregkey = Test-Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\DisableLoopbackCheck"
If ($checkregkey -eq $True) {
Write-Host "'DisableLoopbackCheck' key exists on $mbserver".
}
Else {
Write-Host "'DisableLoopbackCheck' key does not exist on $mbserver."
}
}
}
I have a script that helps a user find if a file hash exists in a folder. After the user has entered the hash I determine what type of hash it is and if it is not supported or if the user missed a letter it will return to asking for a hash. For ease of use I want to be able to pre-fill out what the user had type in the previously so they do not need to start over.
while (1)
{
$hashToFind = Read-Host -Prompt "Enter hash to find or type 'file' for multiple hashes"
# Check if user wants to use text file
if ($hashToFind -eq "file" )
{
Write-Host "Be aware program will only support one has type at a time. Type is determined by the first hash in the file." -ForegroundColor Yellow
Start-Sleep -Seconds 3
$hashPath = New-Object system.windows.forms.openfiledialog
$hashPath.InitialDirectory = “c:\”
$hashPath.MultiSelect = $false
if($hashPath.showdialog() -ne "OK")
{
echo "No file was selected. Exiting program."
Return
}
$hashToFind = Get-Content $hashPath.filename
}
# Changes string to array
if ( $hashToFind.GetTypeCode() -eq "String")
{
$hashToFind+= " a"
$hashToFind = $hashToFind.Split(" ")
}
if ($hashToFind[0].Length -eq 40){$hashType = "SHA1"; break}
elseif ($hashToFind[0].Length -eq 64){$hashType = "SHA256"; break}
elseif ($hashToFind[0].Length -eq 96){$hashType = "SHA384"; break}
elseif ($hashToFind[0].Length -eq 128){$hashType = "SHA512"; break}
elseif ($hashToFind[0].Length -eq 32){$hashType = "MD5"; break}
else {echo "Hash length is not of supported hash type."}
}
I am newer to PowerShell so if there are any other comments they are welcome!
From Super User:
[System.Windows.Forms.SendKeys]::SendWait("yes")
Read-Host "Your answer"
I have came up with solution like this:
while (1)
{
$hashToFind = Read-Host -Prompt "Enter hash to find or type 'file' for multiple hashes. Enter 'R' for reply input"
if ($hashToFind -eq 'R' -and $PreviousInput)
{
$handle = (Get-Process -Id $PID).MainWindowHandle
$code = {
param($handle,$PreviousInput)
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"#
[void][Tricks]::SetForegroundWindow($handle)
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait($PreviousInput)
}
$ps = [PowerShell]::Create()
[void]$ps.AddScript($code).AddArgument($handle).AddArgument($PreviousInput)
[void]$ps.BeginInvoke()
}
$PreviousInput = $hashToFind
# Check if user wants to use text file
if ($hashToFind -eq "file" )
{
$PreviousInput = $null
Write-Host "Be aware program will only support one has type at a time. Type is determined by the first hash in the file." -ForegroundColor Yellow
Start-Sleep -Seconds 3
$hashPath = New-Object system.windows.forms.openfiledialog
$hashPath.InitialDirectory = “c:\”
$hashPath.MultiSelect = $false
if($hashPath.showdialog() -ne "OK")
{
echo "No file was selected. Exiting program."
Return
}
$hashToFind = Get-Content $hashPath.filename
}
# Changes string to array
if ( $hashToFind.GetTypeCode() -eq "String")
{
$hashToFind+= " a"
$hashToFind = $hashToFind.Split(" ")
}
if ($hashToFind[0].Length -eq 40){$hashType = "SHA1"; break}
elseif ($hashToFind[0].Length -eq 64){$hashType = "SHA256"; break}
elseif ($hashToFind[0].Length -eq 96){$hashType = "SHA384"; break}
elseif ($hashToFind[0].Length -eq 128){$hashType = "SHA512"; break}
elseif ($hashToFind[0].Length -eq 32){$hashType = "MD5"; break}
else {echo "Hash length is not of supported hash type."}
}