Jump to content
Sign in to follow this  
MrChiliCheese

Treeview, how to get childrens and grandchildrens?

Recommended Posts

MrChiliCheese

Hi guys,

i know the question sounds funny, but how can i get the (grand)-grandchildren of the selection in a treeview?

If figured out, that i get the childs, when using _GUICtrlTreeView_GetItemByIndex, but i don't know how to realize that...

Here is my script so far...

#include <GUIConstantsEx.au3>
#Include <GUITreeView.au3>
#Include <GUIImageList.au3>
#include <Process.au3>
#include <WindowsConstants.au3>
#include <Array.au3>

GUICreate ("test", 500,600)
$process_treeview = GUICtrlCreateTreeView(5,5,490,490,BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS,$TVS_NOSCROLL))
$bn = GUICtrlCreateButton ("Child", 5,500,80,80)
GUISetState ()

$proc_list = _ProcessListProperties()
_Update()
_ArrayDisplay($proc_list)

While 1
    $msg = GUIGetMsg ()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $bn
            MsgBox(0,"",_GetAllChildItems())
    EndSwitch
WEnd

Exit

Func _GetAllChildItems()
    $text = "Daddy:" & @LF & @TAB & _GUICtrlTreeView_GetText($process_treeview,_GUICtrlTreeView_GetSelection($process_treeview))
    $count = _GUICtrlTreeView_GetChildCount ($process_treeview,_GUICtrlTreeView_GetSelection($process_treeview))
    If $count > 0 Then
        $text &= @LF & @LF & "Kiddies:" 
        For $a = 0 To $count-1
            $text &= @LF & @TAB & _GUICtrlTreeView_GetText($process_treeview,_GUICtrlTreeView_GetItemByIndex ($process_treeview,_GUICtrlTreeView_GetSelection($process_treeview),$a))
        Next
    EndIf
    Return $text
EndFunc

Func _Update()
    _GUICtrlTreeView_BeginUpdate($process_treeview)
    _GUICtrlTreeView_DeleteAll($process_treeview)
    For $a = 1 To $proc_list[0][0]
        If ProcessExists($proc_list[$a][2]) = 0 Then
            $last_id = _GUICtrlTreeView_Add($process_treeview, 0,$proc_list[$a][0])
            $icon = _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,_ProcessGetPath($proc_list[$a][1]))
            If $icon <> True Then
                _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,"shell32.dll",2)
            EndIf
        Else
            $pPID_handle = _GUICtrlTreeView_FindItem($process_treeview, _ProcessGetName ($proc_list[$a][2]))
            $last_id = _GUICtrlTreeView_AddChild($process_treeview, $pPID_handle, $proc_list[$a][0])
            $icon = _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,_ProcessGetPath($proc_list[$a][1]))
            If $icon <> True Then
                _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,"shell32.dll",2)
            EndIf
        EndIf
;~      _GUICtrlTreeView_Sort($process_treeview)
    Next
    _GUICtrlTreeView_Expand($process_treeview)
    _GUICtrlTreeView_EndUpdate($process_treeview)
EndFunc


;===============================================================================
; Function Name:    _ProcessListProperties()
; Description:   Get various properties of a process, or all processes
; Call With:       _ProcessListProperties( [$Process [, $sComputer]] )
; Parameter(s):     (optional) $Process - PID or name of a process, default is "" (all)
;           (optional) $sComputer - remote computer to get list from, default is local
; Requirement(s):   AutoIt v3.2.4.9+
; Return Value(s):  On Success - Returns a 2D array of processes, as in ProcessList()
;             with additional columns added:
;             [0][0] - Number of processes listed (can be 0 if no matches found)
;             [1][0] - 1st process name
;             [1][1] - 1st process PID
;             [1][2] - 1st process Parent PID
;             [1][3] - 1st process owner
;             [1][4] - 1st process priority (0 = low, 31 = high)
;             [1][5] - 1st process executable path
;             [1][6] - 1st process CPU usage
;             [1][7] - 1st process memory usage
;             [1][8] - 1st process creation date/time = "MM/DD/YYY hh:mm:ss" (hh = 00 to 23)
;             [1][9] - 1st process command line string
;             ...
;             [n][0] thru [n][9] - last process properties
; On Failure:       Returns array with [0][0] = 0 and sets @Error to non-zero (see code below)
; Author(s):        PsaltyDS at http://www.autoitscript.com/forum
; Date/Version:   09/17/2008  --  v2.0.3
; Notes:            If an integer PID or string process name is provided and no match is found,
;             then [0][0] = 0 and @error = 0 (not treated as an error, same as ProcessList)
;           This function requires admin permissions to the target computer.
;           All properties come from the Win32_Process class in WMI.
;             To get time-base properties (CPU and Memory usage), a 100ms SWbemRefresher is used.
;===============================================================================
Func _ProcessListProperties($Process = "", $sComputer = ".")
    Local $sUserName, $sMsg, $sUserDomain, $avProcs, $dtmDate
    Local $avProcs[1][2] = [[0, ""]], $n = 1

    ; Convert PID if passed as string
    If StringIsInt($Process) Then $Process = Int($Process)

    ; Connect to WMI and get process objects
    $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy, (Debug)}!\\" & $sComputer & "\root\cimv2")
    If IsObj($oWMI) Then
        ; Get collection processes from Win32_Process
        If $Process = "" Then
            ; Get all
            $colProcs = $oWMI.ExecQuery("select * from win32_process")
        ElseIf IsInt($Process) Then
            ; Get by PID
            $colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & $Process)
        Else
            ; Get by Name
            $colProcs = $oWMI.ExecQuery("select * from win32_process where Name = '" & $Process & "'")
        EndIf

        If IsObj($colProcs) Then
            ; Return for no matches
            If $colProcs.count = 0 Then Return $avProcs

            ; Size the array
            ReDim $avProcs[$colProcs.count + 1][10]
            $avProcs[0][0] = UBound($avProcs) - 1

            ; For each process...
            For $oProc In $colProcs
                ; [n][0] = Process name
                $avProcs[$n][0] = $oProc.name
                ; [n][1] = Process PID
                $avProcs[$n][1] = $oProc.ProcessId
                ; [n][2] = Parent PID
                $avProcs[$n][2] = $oProc.ParentProcessId
                ; [n][3] = Owner
                If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "\" & $sUserName
                ; [n][4] = Priority
                $avProcs[$n][4] = $oProc.Priority
                ; [n][5] = Executable path
                $avProcs[$n][5] = $oProc.ExecutablePath
                ; [n][8] = Creation date/time
                $dtmDate = $oProc.CreationDate
                If $dtmDate <> "" Then
                    ; Back referencing RegExp pattern from weaponx
                    Local $sRegExpPatt = "\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:.*)"
                    $dtmDate = StringRegExpReplace($dtmDate, $sRegExpPatt, "$2/$3/$1 $4:$5:$6")
                EndIf
                $avProcs[$n][8] = $dtmDate
                ; [n][9] = Command line string
                $avProcs[$n][9] = $oProc.CommandLine

                ; increment index
                $n += 1
            Next
        Else
            SetError(2); Error getting process collection from WMI
        EndIf
        ; release the collection object
        $colProcs = 0

        ; Get collection of all processes from Win32_PerfFormattedData_PerfProc_Process
        ; Have to use an SWbemRefresher to pull the collection, or all Perf data will be zeros
        Local $oRefresher = ObjCreate("WbemScripting.SWbemRefresher")
        $colProcs = $oRefresher.AddEnum($oWMI, "Win32_PerfFormattedData_PerfProc_Process" ).objectSet
        $oRefresher.Refresh

        ; Time delay before calling refresher
        Local $iTime = TimerInit()
        Do
            Sleep(20)
        Until TimerDiff($iTime) >= 100
        $oRefresher.Refresh

        ; Get PerfProc data
        For $oProc In $colProcs
            ; Find it in the array
            For $n = 1 To $avProcs[0][0]
                If $avProcs[$n][1] = $oProc.IDProcess Then
                    ; [n][6] = CPU usage
                    $avProcs[$n][6] = $oProc.PercentProcessorTime
                    ; [n][7] = memory usage
                    $avProcs[$n][7] = $oProc.WorkingSet
                    ExitLoop
                EndIf
            Next
        Next
    Else
        SetError(1); Error connecting to WMI
    EndIf

    ; Return array
    Return $avProcs
EndFunc  ;==>_ProcessListProperties

; #FUNCTION# ===============================================================================
; Name...........: _ProcessGetPath(
; Description ...: Retrieves a process file path
; Syntax.........: _ProcessGetPath($vProcess)
; Parameters ....: $vProcess - PID or name of a process
; Requirements...: kernel32.dll, psapi.dll
; Return values .: Success - A full process path
;                     @error = 0
;                    Failure - Empty string
;                     @error = 1 - Invalid process name/PID
;                     @error = 2 - kernel32.dll failed to open (wrong version?)
;                     @error = 3 - Could not OpenProcess
;                      @error = 4 - psapi.dll failed to open (doesn't exist?)
;                     @error = 5 - returned path is empty or invalid
; Author ........: JScript, Larry, SmOke_N
; Modified.......: mrRevoked - reformated, error checking
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......;
; ============================================================================================
Func _ProcessGetPath($vProcess)
    Local $i_PID, $hKernel32, $hPsapi, $aProcessHandle, $tDLLStruct, $iError, $sProcessPath
    
    $i_PID = ProcessExists($vProcess)
    
    If Not $i_PID Then Return SetError(1, 0, "");process doesn't exist?
    
    $hKernel32 = DllOpen("Kernel32.dll")
    $iError = @error
    If $iError Then
        DllClose($hKernel32)
        Return SetError(2, $iError, ""); dllopen kernell32.dll failed
    EndIf
    
    $aProcessHandle = DllCall($hKernel32, "int", "OpenProcess", "int", 0x0400 + 0x0010, "int", 0, "int", $i_PID)
    $iError = @error
    If $iError Or $aProcessHandle[0] = 0 Then
        DllClose($hKernel32)
        Return SetError(2, $iError, "");openprocess failed
    EndIf
    
    $hPsapi = DllOpen("Psapi.dll")
    $iError = @error
    If $iError Then
        DllClose($hKernel32)
        DllClose($hPsapi)
        Return SetError(3, $iError, ""); dllopen psapi.dll failed
    EndIf
    
    $tDLLStruct = DllStructCreate("char[1000]")
    
    DllCall($hPsapi, "long", "GetModuleFileNameEx", "int", $aProcessHandle[0], "int", 0, "ptr", DllStructGetPtr($tDLLStruct), "long", DllStructGetSize($tDLLStruct))
    $iError = @error

    DllCall($hKernel32, "int", "CloseHandle", "int", $aProcessHandle[0])
    DllClose($hKernel32)
    DllClose($hPsapi)
    
    If $iError Then
        $tDLLStruct = 0
        Return SetError(4, $iError, "");getmodulefilenamex failed
    EndIf
    
    $sProcessPath = DllStructGetData($tDLLStruct, 1)
    $tDLLStruct = 0
    
;format the output
    If StringLen($sProcessPath) < 2 Then Return SetError(5, 0, "");is empty or non readable
    If StringLeft($sProcessPath, 4) = "\??\" Then $sProcessPath = StringReplace($sProcessPath, "\??\", "")
    If StringLeft($sProcessPath, 20) = "\SystemRoot\System32" Then $sProcessPath = StringReplace($sProcessPath, "\SystemRoot\System32", @SystemDir)
    
    Return SetError(0, 0, $sProcessPath)
EndFunc;==>_ProcessGetPath

I hope u understand what i want and could help me ^_^

thanks a lot...

Share this post


Link to post
Share on other sites
Authenticity

Using recursion:

#include <GUIConstantsEx.au3>
#Include <GUITreeView.au3>
#Include <GUIImageList.au3>
#include <Process.au3>
#include <WindowsConstants.au3>
#include <Array.au3>

GUICreate ("test", 500,600)
$process_treeview = GUICtrlCreateTreeView(5,5,490,490,BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS,$TVS_NOSCROLL))
$bn = GUICtrlCreateButton ("Child", 5,500,80,80)
$sStr = ''
GUISetState ()

$proc_list = _ProcessListProperties()
_Update()

While 1
    $msg = GUIGetMsg ()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $bn
            $sStr = ''
            _GetAllDescendantItems(_GUICtrlTreeView_GetSelection($process_treeview))
            MsgBox(0,"", $sStr)
    EndSwitch
WEnd

Exit
    
Func _GetAllDescendantItems($hParent)
    $hItem = _GUICtrlTreeView_GetFirstChild($process_treeview, $hParent)
    
    While $hItem
        $sStr &= _GUICtrlTreeView_GetText($process_treeview, $hItem) & @LF
        _GetAllDescendantItems($hItem)
        $hItem = _GUICtrlTreeView_GetNextChild($process_treeview, $hItem)
    WEnd
EndFunc


Func _Update()
    _GUICtrlTreeView_BeginUpdate($process_treeview)
    _GUICtrlTreeView_DeleteAll($process_treeview)
    For $a = 1 To $proc_list[0][0]
        If ProcessExists($proc_list[$a][2]) = 0 Then
            $last_id = _GUICtrlTreeView_Add($process_treeview, 0,$proc_list[$a][0])
            $icon = _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,_ProcessGetPath($proc_list[$a][1]))
            If $icon <> True Then
                _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,"shell32.dll",2)
            EndIf
        Else
            $pPID_handle = _GUICtrlTreeView_FindItem($process_treeview, _ProcessGetName ($proc_list[$a][2]))
            $last_id = _GUICtrlTreeView_AddChild($process_treeview, $pPID_handle, $proc_list[$a][0])
            $icon = _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,_ProcessGetPath($proc_list[$a][1]))
            If $icon <> True Then
                _GUICtrlTreeView_SetIcon ($process_treeview,$last_id,"shell32.dll",2)
            EndIf
        EndIf
;~   _GUICtrlTreeView_Sort($process_treeview)
    Next
    _GUICtrlTreeView_Expand($process_treeview)
    _GUICtrlTreeView_EndUpdate($process_treeview)
EndFunc


;===============================================================================
; Function Name:    _ProcessListProperties()
; Description:   Get various properties of a process, or all processes
; Call With:       _ProcessListProperties( [$Process [, $sComputer]] )
; Parameter(s):     (optional) $Process - PID or name of a process, default is "" (all)
;           (optional) $sComputer - remote computer to get list from, default is local
; Requirement(s):   AutoIt v3.2.4.9+
; Return Value(s):  On Success - Returns a 2D array of processes, as in ProcessList()
;             with additional columns added:
;             [0][0] - Number of processes listed (can be 0 if no matches found)
;             [1][0] - 1st process name
;             [1][1] - 1st process PID
;             [1][2] - 1st process Parent PID
;             [1][3] - 1st process owner
;             [1][4] - 1st process priority (0 = low, 31 = high)
;             [1][5] - 1st process executable path
;             [1][6] - 1st process CPU usage
;             [1][7] - 1st process memory usage
;             [1][8] - 1st process creation date/time = "MM/DD/YYY hh:mm:ss" (hh = 00 to 23)
;             [1][9] - 1st process command line string
;             ...
;             [n][0] thru [n][9] - last process properties
; On Failure:       Returns array with [0][0] = 0 and sets @Error to non-zero (see code below)
; Author(s):        PsaltyDS at http://www.autoitscript.com/forum
; Date/Version:   09/17/2008  --  v2.0.3
; Notes:            If an integer PID or string process name is provided and no match is found,
;             then [0][0] = 0 and @error = 0 (not treated as an error, same as ProcessList)
;           This function requires admin permissions to the target computer.
;           All properties come from the Win32_Process class in WMI.
;             To get time-base properties (CPU and Memory usage), a 100ms SWbemRefresher is used.
;===============================================================================
Func _ProcessListProperties($Process = "", $sComputer = ".")
    Local $sUserName, $sMsg, $sUserDomain, $avProcs, $dtmDate
    Local $avProcs[1][2] = [[0, ""]], $n = 1

    ; Convert PID if passed as string
    If StringIsInt($Process) Then $Process = Int($Process)

    ; Connect to WMI and get process objects
    $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy, (Debug)}!\\" & $sComputer & "\root\cimv2")
    If IsObj($oWMI) Then
        ; Get collection processes from Win32_Process
        If $Process = "" Then
            ; Get all
            $colProcs = $oWMI.ExecQuery("select * from win32_process")
        ElseIf IsInt($Process) Then
            ; Get by PID
            $colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & $Process)
        Else
            ; Get by Name
            $colProcs = $oWMI.ExecQuery("select * from win32_process where Name = '" & $Process & "'")
        EndIf

        If IsObj($colProcs) Then
            ; Return for no matches
            If $colProcs.count = 0 Then Return $avProcs

            ; Size the array
            ReDim $avProcs[$colProcs.count + 1][10]
            $avProcs[0][0] = UBound($avProcs) - 1

            ; For each process...
            For $oProc In $colProcs
                ; [n][0] = Process name
                $avProcs[$n][0] = $oProc.name
                ; [n][1] = Process PID
                $avProcs[$n][1] = $oProc.ProcessId
                ; [n][2] = Parent PID
                $avProcs[$n][2] = $oProc.ParentProcessId
                ; [n][3] = Owner
                If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "\" & $sUserName
                ; [n][4] = Priority
                $avProcs[$n][4] = $oProc.Priority
                ; [n][5] = Executable path
                $avProcs[$n][5] = $oProc.ExecutablePath
                ; [n][8] = Creation date/time
                $dtmDate = $oProc.CreationDate
                If $dtmDate <> "" Then
                    ; Back referencing RegExp pattern from weaponx
                    Local $sRegExpPatt = "\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:.*)"
                    $dtmDate = StringRegExpReplace($dtmDate, $sRegExpPatt, "$2/$3/$1 $4:$5:$6")
                EndIf
                $avProcs[$n][8] = $dtmDate
                ; [n][9] = Command line string
                $avProcs[$n][9] = $oProc.CommandLine

                ; increment index
                $n += 1
            Next
        Else
            SetError(2); Error getting process collection from WMI
        EndIf
        ; release the collection object
        $colProcs = 0

        ; Get collection of all processes from Win32_PerfFormattedData_PerfProc_Process
        ; Have to use an SWbemRefresher to pull the collection, or all Perf data will be zeros
        Local $oRefresher = ObjCreate("WbemScripting.SWbemRefresher")
        $colProcs = $oRefresher.AddEnum($oWMI, "Win32_PerfFormattedData_PerfProc_Process" ).objectSet
        $oRefresher.Refresh

        ; Time delay before calling refresher
        Local $iTime = TimerInit()
        Do
            Sleep(20)
        Until TimerDiff($iTime) >= 100
        $oRefresher.Refresh

        ; Get PerfProc data
        For $oProc In $colProcs
            ; Find it in the array
            For $n = 1 To $avProcs[0][0]
                If $avProcs[$n][1] = $oProc.IDProcess Then
                    ; [n][6] = CPU usage
                    $avProcs[$n][6] = $oProc.PercentProcessorTime
                    ; [n][7] = memory usage
                    $avProcs[$n][7] = $oProc.WorkingSet
                    ExitLoop
                EndIf
            Next
        Next
    Else
        SetError(1); Error connecting to WMI
    EndIf

    ; Return array
    Return $avProcs
EndFunc  ;==>_ProcessListProperties

; #FUNCTION# ===============================================================================
; Name...........: _ProcessGetPath(
; Description ...: Retrieves a process file path
; Syntax.........: _ProcessGetPath($vProcess)
; Parameters ....: $vProcess - PID or name of a process
; Requirements...: kernel32.dll, psapi.dll
; Return values .: Success - A full process path
;                     @error = 0
;                    Failure - Empty string
;                     @error = 1 - Invalid process name/PID
;                     @error = 2 - kernel32.dll failed to open (wrong version?)
;                     @error = 3 - Could not OpenProcess
;                      @error = 4 - psapi.dll failed to open (doesn't exist?)
;                     @error = 5 - returned path is empty or invalid
; Author ........: JScript, Larry, SmOke_N
; Modified.......: mrRevoked - reformated, error checking
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......;
; ============================================================================================
Func _ProcessGetPath($vProcess)
    Local $i_PID, $hKernel32, $hPsapi, $aProcessHandle, $tDLLStruct, $iError, $sProcessPath
   
    $i_PID = ProcessExists($vProcess)
   
    If Not $i_PID Then Return SetError(1, 0, "");process doesn't exist?
   
    $hKernel32 = DllOpen("Kernel32.dll")
    $iError = @error
    If $iError Then
        DllClose($hKernel32)
        Return SetError(2, $iError, ""); dllopen kernell32.dll failed
    EndIf
   
    $aProcessHandle = DllCall($hKernel32, "int", "OpenProcess", "int", 0x0400 + 0x0010, "int", 0, "int", $i_PID)
    $iError = @error
    If $iError Or $aProcessHandle[0] = 0 Then
        DllClose($hKernel32)
        Return SetError(2, $iError, "");openprocess failed
    EndIf
   
    $hPsapi = DllOpen("Psapi.dll")
    $iError = @error
    If $iError Then
        DllClose($hKernel32)
        DllClose($hPsapi)
        Return SetError(3, $iError, ""); dllopen psapi.dll failed
    EndIf
   
    $tDLLStruct = DllStructCreate("char[1000]")
   
    DllCall($hPsapi, "long", "GetModuleFileNameEx", "int", $aProcessHandle[0], "int", 0, "ptr", DllStructGetPtr($tDLLStruct), "long", DllStructGetSize($tDLLStruct))
    $iError = @error

    DllCall($hKernel32, "int", "CloseHandle", "int", $aProcessHandle[0])
    DllClose($hKernel32)
    DllClose($hPsapi)
   
    If $iError Then
        $tDLLStruct = 0
        Return SetError(4, $iError, "");getmodulefilenamex failed
    EndIf
   
    $sProcessPath = DllStructGetData($tDLLStruct, 1)
    $tDLLStruct = 0
   
;format the output
    If StringLen($sProcessPath) < 2 Then Return SetError(5, 0, "");is empty or non readable
    If StringLeft($sProcessPath, 4) = "\??\" Then $sProcessPath = StringReplace($sProcessPath, "\??\", "")
    If StringLeft($sProcessPath, 20) = "\SystemRoot\System32" Then $sProcessPath = StringReplace($sProcessPath, "\SystemRoot\System32", @SystemDir)
   
    Return SetError(0, 0, $sProcessPath)
EndFunc;==>_ProcessGetPath

Share this post


Link to post
Share on other sites
MrChiliCheese

Thank you very much... i tried something like that, but i didn't get thtat in my mind... recursion a very cool ^_^

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.