@@ -30,7 +30,7 @@ Global $_g_bNetWebView2_DebugInfo = True
3030; ~ Global $_g_bNetWebView2_DebugDev = False
3131Global $_g_bNetWebView2_DebugDev = (@Compiled = 1 )
3232
33- #Region ; ENUMS
33+ #Region ; === NetWebView2Lib UDF === ENUMS
3434
3535; ~ Global Enum _
3636; ~ $NETWEBVIEW2_ERR__INIT_FAILED, _
@@ -116,9 +116,9 @@ Global Enum _ ; Indicates the reason for the process failure.
116116 $NETWEBVIEW2_PROCESS_FAILED_REASON_CRASHED , _
117117 $NETWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED , _
118118 $NETWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY
119- #EndRegion ; ENUMS
119+ #EndRegion ; === NetWebView2Lib UDF === ENUMS
120120
121- #Region ; NetWebView2Lib UDF - _NetWebView2_* core functions
121+ #Region ; === NetWebView2Lib UDF === _NetWebView2_* core functions
122122; #FUNCTION# ====================================================================================================================
123123; Name ..........: _NetWebView2_CreateManager
124124; Description ...: Create WebView2 object
@@ -238,54 +238,6 @@ Func _NetWebView2_Initialize($oWebV2M, $hUserGUI, $s_ProfileDirectory, $i_Left =
238238 Return SetError (@error , $oWebV2M .GetBrowserProcessId(), $iInit )
239239EndFunc ; ==>_NetWebView2_Initialize
240240
241- ; #INTERNAL_USE_ONLY# ===========================================================================================================
242- ; Name ..........: __NetWebView2_WaitForReadyState
243- ; Description ...: Polls the browser until the document.readyState reaches 'complete'.
244- ; Syntax ........: __NetWebView2_WaitForReadyState($oWebV2M, $hTimer[, $iTimeOut_ms = 5000])
245- ; Parameters ....: $oWebV2M - The WebView2 Manager object.
246- ; $hTimer - a handle to a caller TimerInit
247- ; $iTimeOut_ms - [optional] Maximum time to wait in milliseconds. 0 for infinite. Default is 5000ms
248- ; Return values .: Success: True
249- ; Failure: False, sets @error:
250- ; 1 - Timeout reached before document was complete.
251- ; 2 - WebView2 object is not valid or ready.
252- ; Author ........: ioa747, mLipok
253- ; Modified.......:
254- ; Remarks .......: This function uses JavaScript execution to check the internal state of the page.
255- ; Useful for tasks like PDF printing where 'complete' state is mandatory.
256- ; ===============================================================================================================================
257- Func __NetWebView2_WaitForReadyState($oWebV2M , $hTimer , $iTimeOut_ms = 5000 )
258- Local Const $s_Prefix = " >>>[_NetWebView2_WaitForReadyState]:"
259-
260- If (Not IsObj ($oWebV2M )) Or ObjName ($oWebV2M , $OBJ_PROGID ) <> ' NetWebView2Lib.WebView2Manager' Then Return SetError (2 , 0 , False )
261- Local $sReadyState = " "
262-
263- While 1
264- ; Execute JS via the Bridge (Mode 2)
265- $sReadyState = _NetWebView2_ExecuteScript($oWebV2M , " document.readyState" , $NETWEBVIEW2_EXECUTEJS_MODE2_RESULT )
266- If @error Then Return SetError (@error , @extended , False )
267-
268- ; Check for the 'complete' state
269- If $sReadyState == " complete" Then
270- __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " SUCCESS: Document is ready. Timeout_ms: " & Round (TimerDiff ($hTimer ), 0 ), 0 )
271- Return True
272- EndIf
273-
274- ; Check for C# Bridge internal errors (Timeout/Init)
275- If StringLeft ($sReadyState , 6 ) == " ERROR:" Then
276- __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " BRIDGE " & $sReadyState & " Timeout_ms: " & Round (TimerDiff ($hTimer ), 0 ), 1 )
277- Return SetError (3 , 0 , False )
278- EndIf
279-
280- ; Check for AutoIt-side Timeout
281- If $iTimeOut_ms > 0 And TimerDiff ($hTimer ) > $iTimeOut_ms Then
282- __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " TIMEOUT: Document state is " & $sReadyState & " Timeout_ms: " & Round (TimerDiff ($hTimer ), 0 ), 1 )
283- Return SetError (1 , 0 , False )
284- EndIf
285- Sleep (50 )
286- WEnd
287- EndFunc ; ==>__NetWebView2_WaitForReadyState
288-
289241; #FUNCTION# ====================================================================================================================
290242; Name ..........: _NetWebView2_IsRegisteredCOMObject
291243; Description ...: Check if all necessary object are registerd
@@ -671,9 +623,9 @@ Func _NetWebView2_NavigateToString($oWebV2M, $s_HTML, $iWaitMessage = $NETWEBVIE
671623 EndIf
672624EndFunc ; ==>_NetWebView2_NavigateToString
673625
674- #EndRegion ; NetWebView2Lib UDF - _NetWebView2_* core functions
626+ #EndRegion ; === NetWebView2Lib UDF === _NetWebView2_* core functions
675627
676- #Region ; NetWebView2Lib UDF - _NetWebView2_* helper functions
628+ #Region ; === NetWebView2Lib UDF === _NetWebView2_* helper functions
677629; #FUNCTION# ====================================================================================================================
678630; Name ..........: _NetWebView2_BrowserSetupWrapper
679631; Description ...:
@@ -856,9 +808,9 @@ Func _NetWebView2_PrintToPdfStream($oWebV2M, $b_TBinary_FBase64)
856808 Return SetError (@error , @extended , $s_Result )
857809EndFunc ; ==>_NetWebView2_PrintToPdfStream
858810
859- #EndRegion ; NetWebView2Lib UDF - _NetWebView2_* helper functions
811+ #EndRegion ; === NetWebView2Lib UDF === _NetWebView2_* helper functions
860812
861- #Region ; New Core Method Wrappers
813+ #Region ; === NetWebView2Lib UDF === New Core Method Wrappers
862814; #FUNCTION# ====================================================================================================================
863815; Name...........: _NetWebView2_AddInitializationScript
864816; Description ...: Adds a JavaScript to be executed before any other script when a new page is loaded.
@@ -1015,21 +967,6 @@ Func _NetWebView2_SetBuiltInErrorPageEnabled($oWebV2M, $bEnabled)
1015967 Return SetError (@error , 0 , (@error ? False : True ))
1016968EndFunc ; ==>_NetWebView2_SetBuiltInErrorPageEnabled
1017969
1018- ; #FUNCTION# ====================================================================================================================
1019- ; Name...........: _NetWebView2_SilentErrorHandler
1020- ; Description....: A generic COM Error Handler that silences errors.
1021- ; Syntax.........: _NetWebView2_SilentErrorHandler()
1022- ; Remarks........: Used to prevent script crashes when a WebView2 object is disposed or closed
1023- ; while an event or a method call is still in progress.
1024- ; Author ........: ioa747, mLipok
1025- ; ===============================================================================================================================
1026- Volatile Func _NetWebView2_SilentErrorHandler($oError )
1027- #forceref $oError
1028- ; We do nothing, effectively "swallowing" the COM error.
1029- ; This prevents the "Object Disposed" fatal crash.
1030- $oError = 0 ; Explicitly release the COM reference inside the volatile scopeEndFunc
1031- EndFunc ; ==>_NetWebView2_SilentErrorHandler
1032-
1033970; #FUNCTION# ====================================================================================================================
1034971; Name...........: _WebView2_FrameGetHtmlSource
1035972; Description....: Synchronously retrieves the full HTML source of a frame.
@@ -1070,9 +1007,9 @@ Func _WebView2_FrameGetHtmlSource($oFrame)
10701007 Return $sClean
10711008EndFunc ; ==>_WebView2_FrameGetHtmlSource
10721009
1073- #EndRegion ; New Core Method Wrappers
1010+ #EndRegion ; === NetWebView2Lib UDF === New Core Method Wrappers
10741011
1075- #Region ; NetWebView2Lib UDF - _NetJson_* functions
1012+ #Region ; === NetWebView2Lib UDF === _NetJson_* functions
10761013; #FUNCTION# ====================================================================================================================
10771014; Name ..........: _NetJson_CreateParser
10781015; Description ...:
@@ -1120,13 +1057,13 @@ Func _NetJson_DecodeB64($sData)
11201057 Local $oMyError = ObjEvent (" AutoIt.Error" , __NetWebView2_COMErrFunc) ; Local COM Error Handler
11211058 #forceref $oMyError
11221059
1123- Local $oJSON = _NetJson_CreateParser()
1060+ Local $oJson = _NetJson_CreateParser()
11241061 If @error Then
11251062 __NetWebView2_Log(@ScriptLineNumber , $s_Prefix , 1 )
1126- Return SetError (@error , @extended , $oJSON )
1063+ Return SetError (@error , @extended , $oJson )
11271064 EndIf
11281065
1129- Local $dBinary = $oJSON .Decode64($sData )
1066+ Local $dBinary = $oJson .Decode64($sData )
11301067 If @error Then __NetWebView2_Log(@ScriptLineNumber , $s_Prefix , 1 )
11311068 Return SetError (@error , @extended , $dBinary )
11321069EndFunc ; ==>_NetJson_DecodeB64
@@ -1149,19 +1086,67 @@ Func _NetJson_EncodeB64($sData)
11491086 Local $oMyError = ObjEvent (" AutoIt.Error" , __NetWebView2_COMErrFunc) ; Local COM Error Handler
11501087 #forceref $oMyError
11511088
1152- Local $oJSON = _NetJson_CreateParser()
1089+ Local $oJson = _NetJson_CreateParser()
11531090 If @error Then
11541091 __NetWebView2_Log(@ScriptLineNumber , $s_Prefix , 1 )
1155- Return SetError (@error , @extended , $oJSON )
1092+ Return SetError (@error , @extended , $oJson )
11561093 EndIf
11571094
1158- Local $vResult = $oJSON .EncodeB64($sData )
1095+ Local $vResult = $oJson .EncodeB64($sData )
11591096 If @error Then __NetWebView2_Log(@ScriptLineNumber , $s_Prefix , 1 )
11601097 Return SetError (@error , @extended , $vResult )
11611098EndFunc ; ==>_NetJson_EncodeB64
1162- #EndRegion ; NetWebView2Lib UDF - _NetJson_* functions
1099+ #EndRegion ; === NetWebView2Lib UDF === _NetJson_* functions
1100+
1101+ #Region ; === NetWebView2Lib UDF === #INTERNAL_USE_ONLY#
1102+ ; #INTERNAL_USE_ONLY# ===========================================================================================================
1103+ ; Name ..........: __NetWebView2_WaitForReadyState
1104+ ; Description ...: Polls the browser until the document.readyState reaches 'complete'.
1105+ ; Syntax ........: __NetWebView2_WaitForReadyState($oWebV2M, $hTimer[, $iTimeOut_ms = 5000])
1106+ ; Parameters ....: $oWebV2M - The WebView2 Manager object.
1107+ ; $hTimer - a handle to a caller TimerInit
1108+ ; $iTimeOut_ms - [optional] Maximum time to wait in milliseconds. 0 for infinite. Default is 5000ms
1109+ ; Return values .: Success: True
1110+ ; Failure: False, sets @error:
1111+ ; 1 - Timeout reached before document was complete.
1112+ ; 2 - WebView2 object is not valid or ready.
1113+ ; Author ........: ioa747, mLipok
1114+ ; Modified.......:
1115+ ; Remarks .......: This function uses JavaScript execution to check the internal state of the page.
1116+ ; Useful for tasks like PDF printing where 'complete' state is mandatory.
1117+ ; ===============================================================================================================================
1118+ Func __NetWebView2_WaitForReadyState($oWebV2M , $hTimer , $iTimeOut_ms = 5000 )
1119+ Local Const $s_Prefix = " >>>[_NetWebView2_WaitForReadyState]:"
1120+
1121+ If (Not IsObj ($oWebV2M )) Or ObjName ($oWebV2M , $OBJ_PROGID ) <> ' NetWebView2Lib.WebView2Manager' Then Return SetError (2 , 0 , False )
1122+ Local $sReadyState = " "
1123+
1124+ While 1
1125+ ; Execute JS via the Bridge (Mode 2)
1126+ $sReadyState = _NetWebView2_ExecuteScript($oWebV2M , " document.readyState" , $NETWEBVIEW2_EXECUTEJS_MODE2_RESULT )
1127+ If @error Then Return SetError (@error , @extended , False )
1128+
1129+ ; Check for the 'complete' state
1130+ If $sReadyState == " complete" Then
1131+ __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " SUCCESS: Document is ready. Timeout_ms: " & Round (TimerDiff ($hTimer ), 0 ), 0 )
1132+ Return True
1133+ EndIf
1134+
1135+ ; Check for C# Bridge internal errors (Timeout/Init)
1136+ If StringLeft ($sReadyState , 6 ) == " ERROR:" Then
1137+ __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " BRIDGE " & $sReadyState & " Timeout_ms: " & Round (TimerDiff ($hTimer ), 0 ), 1 )
1138+ Return SetError (3 , 0 , False )
1139+ EndIf
1140+
1141+ ; Check for AutoIt-side Timeout
1142+ If $iTimeOut_ms > 0 And TimerDiff ($hTimer ) > $iTimeOut_ms Then
1143+ __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " TIMEOUT: Document state is " & $sReadyState & " Timeout_ms: " & Round (TimerDiff ($hTimer ), 0 ), 1 )
1144+ Return SetError (1 , 0 , False )
1145+ EndIf
1146+ Sleep (50 )
1147+ WEnd
1148+ EndFunc ; ==>__NetWebView2_WaitForReadyState
11631149
1164- #Region ; NetWebView2Lib UDF - #INTERNAL_USE_ONLY#
11651150; #INTERNAL_USE_ONLY# ===========================================================================================================
11661151; Name...........: __NetWebView2_LastMessage_KEEPER
11671152; Description....: Centralized state manager for WebView2 instances using a static map.
@@ -1180,7 +1165,7 @@ EndFunc ;==>_NetJson_EncodeB64
11801165Func __NetWebView2_LastMessage_KEEPER($oWebV2M , $iMessage = Default , $iError = @error , $iExtended = @extended )
11811166 ; Static Map - The central database of status indexed by Window Handle
11821167 ; Local COM Error Handler to trap 0x80020009 (Disposed Object) during closure
1183- Local $oMyError = ObjEvent (" AutoIt.Error" , _NetWebView2_SilentErrorHandler )
1168+ Local $oMyError = ObjEvent (" AutoIt.Error" , __NetWebView2_SilentErrorHandler )
11841169 #forceref $oMyError
11851170
11861171 Local Static $mLastMessegKeeper []
@@ -1200,7 +1185,7 @@ EndFunc ;==>__NetWebView2_LastMessage_KEEPER
12001185Func __NetWebView2_LastMessage_onReceived($oWebV2M , $iMessage = Default , $iError = @error , $iExtended = @extended )
12011186 ; Static Map - The central database of status indexed by Window Handle
12021187 ; Local COM Error Handler to trap 0x80020009 (Disposed Object) during closure
1203- Local $oMyError = ObjEvent (" AutoIt.Error" , _NetWebView2_SilentErrorHandler )
1188+ Local $oMyError = ObjEvent (" AutoIt.Error" , __NetWebView2_SilentErrorHandler )
12041189 #forceref $oMyError
12051190
12061191 Local Static $mLastMessegReceived []
@@ -1217,7 +1202,7 @@ EndFunc ;==>__NetWebView2_LastMessage_onReceived
12171202Func __NetWebView2_LastMessage_Navigation($oWebV2M , $iMessage = Default , $iError = @error , $iExtended = @extended )
12181203 ; Static Map - The central database of status indexed by Window Handle
12191204 ; Local COM Error Handler to trap 0x80020009 (Disposed Object) during closure
1220- Local $oMyError = ObjEvent (" AutoIt.Error" , _NetWebView2_SilentErrorHandler )
1205+ Local $oMyError = ObjEvent (" AutoIt.Error" , __NetWebView2_SilentErrorHandler )
12211206 #forceref $oMyError
12221207
12231208 Local Static $mLastNavigationMessage []
@@ -1482,11 +1467,26 @@ Func __NetWebView2_freezer($oWebV2M, ByRef $idPic)
14821467 #EndRegion ; freeze $hWindow_WebView2
14831468EndFunc ; ==>__NetWebView2_freezer
14841469
1485- #EndRegion ; NetWebView2Lib UDF - #INTERNAL_USE_ONLY#
1470+ #EndRegion ; === NetWebView2Lib UDF === #INTERNAL_USE_ONLY#
14861471
1487- #Region ; === NetWebView2Lib UDF === EVENT HANDLERS ===
1472+ #Region ; === NetWebView2Lib UDF === EVENT HANDLERS === Collection ===
1473+
1474+ #Region ; === NetWebView2Lib UDF === EVENT HANDLERS === Error Handlers ===
1475+ ; #INTERNAL_USE_ONLY# ===========================================================================================================
1476+ ; Name...........: __NetWebView2_SilentErrorHandler
1477+ ; Description....: A generic COM Error Handler that silences errors.
1478+ ; Syntax.........: __NetWebView2_SilentErrorHandler()
1479+ ; Remarks........: Used to prevent script crashes when a WebView2 object is disposed or closed
1480+ ; while an event or a method call is still in progress.
1481+ ; Author ........: ioa747, mLipok
1482+ ; ===============================================================================================================================
1483+ Volatile Func __NetWebView2_SilentErrorHandler($oError )
1484+ #forceref $oError
1485+ ; We do nothing, effectively "swallowing" the COM error.
1486+ ; This prevents the "Object Disposed" fatal crash.
1487+ $oError = 0 ; Explicitly release the COM reference inside the volatile scopeEndFunc
1488+ EndFunc ; ==>__NetWebView2_SilentErrorHandler
14881489
1489- #Region ; === EVENT HANDLERS === Error Handler ===
14901490; #INTERNAL_USE_ONLY# ===========================================================================================================
14911491; Name ..........: __NetWebView2_COMErrFunc
14921492; Description ...:
@@ -1522,9 +1522,9 @@ Volatile Func __NetWebView2_fake_COMErrFunc($oError) ; COM Error Function used b
15221522 ; this is only to silently handle _NetWebView2_IsRegisteredCOMObject()
15231523 $oError = 0 ; Explicitly release the COM reference inside the volatile scopeEndFunc
15241524EndFunc ; ==>__NetWebView2_fake_COMErrFunc
1525- #EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS === Error Handler ===
1525+ #EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS === Error Handlers ===
15261526
1527- #Region ; === EVENT HANDLERS === MessageReceived ===
1527+ #Region ; === NetWebView2Lib UDF === EVENT HANDLERS === MessageReceived ===
15281528; #INTERNAL_USE_ONLY# ===========================================================================================================
15291529; Name ..........: __NetWebView2_Events__OnMessageReceived
15301530; Description ...: Handles native WebView2 events
@@ -1755,18 +1755,18 @@ Volatile Func __NetWebView2_JSEvents__OnMessageReceived($oWebV2M, $hGUI, $sMsg)
17551755 ; 1. Modern JSON Messaging
17561756 If $sFirstChar = " {" Or $sFirstChar = " [" Then
17571757 __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " Processing JSON message..." , 1 )
1758- Local $oJSON = _NetJson_CreateParser()
1759- If @error Or Not IsObj ($oJSON ) Then
1758+ Local $oJson = _NetJson_CreateParser()
1759+ If @error Or Not IsObj ($oJson ) Then
17601760 __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " ERROR: Failed to create NetJson object." , 1 )
1761- Return SetError (@error , @extended , $oJSON )
1761+ Return SetError (@error , @extended , $oJson )
17621762 EndIf
17631763
1764- $oJSON .Parse($sMsg )
1765- Local $sJobType = $oJSON .GetTokenValue(" type" )
1764+ $oJson .Parse($sMsg )
1765+ Local $sJobType = $oJson .GetTokenValue(" type" )
17661766
17671767 Switch $sJobType
17681768 Case " COM_TEST"
1769- __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " COM_TEST Confirmed: " & $oJSON .GetTokenValue(" status" ), 1 )
1769+ __NetWebView2_Log(@ScriptLineNumber , $s_Prefix & " COM_TEST Confirmed: " & $oJson .GetTokenValue(" status" ), 1 )
17701770 EndSwitch
17711771
17721772 Else
@@ -1807,7 +1807,7 @@ Volatile Func __NetWebView2_JSEvents__OnMessageReceived($oWebV2M, $hGUI, $sMsg)
18071807EndFunc ; ==>__NetWebView2_JSEvents__OnMessageReceived
18081808#EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS === MessageReceived ===
18091809
1810- #Region ; === EVENT HANDLERS === Browser ===
1810+ #Region ; === NetWebView2Lib UDF === EVENT HANDLERS === Browser ===
18111811; #INTERNAL_USE_ONLY# ===========================================================================================================
18121812; Name ..........: __NetWebView2_Events__OnBrowserGotFocus
18131813; Description ...:
@@ -2191,7 +2191,7 @@ Volatile Func __NetWebView2_Events__OnBasicAuthenticationRequested($oWebV2M, $hG
21912191EndFunc ; ==>__NetWebView2_Events__OnBasicAuthenticationRequested
21922192#EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS === Browser ===
21932193
2194- #Region ; === EVENT HANDLERS === Frame Related ===
2194+ #Region ; === NetWebView2Lib UDF === EVENT HANDLERS === Frame Related ===
21952195; #INTERNAL_USE_ONLY# ===========================================================================================================
21962196; Name ..........: _NetWebView2_GetFrame
21972197; Description ...: Returns a Frame Object (IWebView2Frame) for the specified index.
@@ -2381,9 +2381,17 @@ Volatile Func __NetWebView2_Events__OnFrameWebMessageReceived($oWebV2M, $hGUI, $
23812381 __NetWebView2_Log(@ScriptLineNumber , $s_Prefix , 1 )
23822382 ; __NetWebView2_LastMessage_KEEPER($oWebV2M, $NETWEBVIEW2_MESSAGE__FRAME_WEB_MESSAGE_RECEIVED)
23832383EndFunc ; ==>__NetWebView2_Events__OnFrameWebMessageReceived
2384+
2385+ Func __NetWebView2_Events__FrameKeeper($oWebV2M , $hGUI , $oFrame )
2386+ #TODO mLipok
2387+ #forceref $oWebV2M, $hGUI, $oFrame
2388+ ; ~ Local Static $aFrames[0][2]
2389+ ; ~ Local Const $aFrameTemplate
2390+ ; ~
2391+ EndFunc ; ==>__NetWebView2_Events__FrameKeeper
23842392#EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS === Frame Related ===
23852393
2386- #Region ; === EVENT HANDLERS * #TODO ===
2394+ #Region ; === NetWebView2Lib UDF === EVENT HANDLERS * #TODO ===
23872395; ~ is this followed webmessagereceived are the same as __NetWebView2_Events__OnMessageReceived() ?
23882396; ~ https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2frame?view=webview2-winrt-1.0.3595.46#webmessagereceived
23892397
@@ -2392,7 +2400,4 @@ EndFunc ;==>__NetWebView2_Events__OnFrameWebMessageReceived
23922400; ~ EndFunc ;==>__NetWebView2_Events__OnScreenCaptureStarting
23932401#EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS * #TODO ===
23942402
2395- #EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS ===
2396-
2397-
2398-
2403+ #EndRegion ; === NetWebView2Lib UDF === EVENT HANDLERS === Collection ===
0 commit comments