3 , . , , , , . SourceCode\ BugslayerUtil\Tests - , BUGSLAYERUTIL.DLL. , .
, (UI) . Tester, UI. , , Tester , . , Tester , , .
, Microsoft , , . 5000- <Alt>+<F>, <> , . , , , . , .
. , Recorder, Windows 3.x, 32- . Recorder ( ) , ( ). , (, , , , . .), -. .
, , . , , Recorder. Windows 3.x REC- . . , Recorder , . , WINFILE.EXE, , Recorder \System.
if. . .then. . .else.
, . , , , YACC FLEX. , , Tester - , , ; (regression-testing) . Microsoft Visual Basic Scripting Edition (VBScript) Java Script (JScript), . Scripting Host (WSH) , . , Tester.
, Tester , , : , . , , , . Tester .
Tester:
1. , ().
2. , , VB- sendKeys, Tester .
3. Tester .
4. HWND Tester .
5. Tester , .
6. Tester .
7. Tester .
, . , , , , : "" , . . , . , , UI . , , UI "", . , , UI "".
Tester, , 20 (Quality Assurance QA). , , . , Tester . GUI- WDBG, 4, !
Tester . Tester-, , , . 13-1 VBScript-, (NOTEPAD.EXE), .
13-1. Tester-
' VBScript Tester.
' , .
' .
Dim tSystem
Dim tInput
Dim twin
Set tSystem = «Script.CreateObject ( "Tester.TSystem")
Set tInput = WScript.CreateObject ( "Tester.TInput")
' .
tSystem.Execute "NOTEPAD.EXE"
' 200 .
tSystem.Pause 200
' .
Set twin = tSystem.FindTopWindowByTitle ( "Untitled - Notepad")
If ( twin Is Nothing) Then
MsgBox "Unable to find Notepad!"
WScript.Quit
End If
' , .
twin.SetForegroundTWindow
' () .
tlnput.PlayKeys "Be all you can be!~ ~ ~"
' .
tlnput.PlayKeys "Put on your boots and parachutes....~ ~ ~"
' .
tlnput.PlayKeys "Silver wings upon their chests.....~ ~ ~"
' 1 .
tSystem.Pause 1000
' .
tlnput.PlayKeys "%FX"
tSystem.Pause 50
tlnput.PlayKeys "{TAB}~"
' !
13-1 , Tester . TSystem , . TWindow, FindTopWindowByritie 13-1, " ". HWND ( ), . , TWindow , . Tlnput, PlayKeys, , .
13-2 TNotify, VBScript-. , , . TNotify , , . , 13-2, "".
13-2. TNotify VBScript
' VBScript-
' TNotify.AddNotification .
' Visual Basic 6, enum .
Const antDestroyWindow = 1
Const antCreateWindow = 2
Const antCreateAndDestroy = 3
Const ansExactMatch = 0
Const ansBeginMatch = 1
Const ansAnyLocMatch = 2
' tSystem tInput.
Dim tSystem
Dim tInput
Set tSystem = WScript.CreateObject ( "Tester.TSystem")
Set tlnput = WScript.CreateObject ( "Tester.Tlnput")
' TNotify
Dim Notifier
' TNotify.
Set Notifier =
WScript.CreateObject ( "Tester.TNotify" ,' _
"NotepadNotification_" )
' .
' window destroy ( )
'window create ( ).
'. TNotify .
Notifier.AddNotification antCreateAndDestroy, _
ansAnyLocMatch ,
_ "Notepad"
' .
tSystem.Execute "NOTEPAD.EXE"
' .
tSystem.Pause 500
' - Visual Basic ,
' Because Visual Basic isn't thread-safe
' , .
' ,
' .
' window create window destroy.
Notifier.CheckNotification
' NotepadNotification_CreateWindow
' ,
', ,
tInput.PlayKeys "%FX"
tSystem.Pause 50
tlnput.PlayKeys "{TAB}-"
' .
Notifier.CheckNotification
' TNotify .
tSystem.Pause 100
' . WSH,
' ,
' .
WScript.DisconnectObject Notifier
Set Notifier = Nothing
Sub NotepadNotificationCreateWindow ( twin)
MsgBox ( "Notepad was created!")
End Sub
Sub NotepadNotificationDestroyWindow ()
MsgBox ( "Notepad has gone away....")
End Sub
TNotify checkNotification. ( , " Tester" ). checkNotification , , , , , . 13-2 , , , , , .
, , TNotify , File Save. TNotify . , , , , , . , , "", , . , TNotify AddNotification . CreateWindow TWindow-, , . DestroyWindow, , , , , , .
, -, , , . .
- Tester. , NPAD_TEST.VBS VBScript-, . ( Tester Tester'a) Tester, . TESTER.VBG.TT VB-, Tester'a Visual Basic. , TWindows, , TWindow.
VBScript , , . VBScript- VBScript , Visual Basic, . VBScript , . , , Visual Basic, , . , Tester , (MASM), VBScript.
Tester'e , , . . , . , , . . , : , . , , . , .
Tester'a, : " , ?". , , , , . Windows (WSH- CSCRIPT.EXE), , wscript.Echo, . , ( WinDiff); - , . , , . , , , .
Tester'a? Tester , a Visual Basic , , Tinput.piayKeys. , , , . , piayKeys , , ( TWindow.SetForegroundTWindow). , SetForegroundTwindow, .
Tester'a, . Tester'a C++ (Active Template Library ATL), , Visual Basic. , Tester'e, , . Visual Basic, , , , .
Tinput, , . , , VB- SendKeys. , , Microsoft Outlook 2000, , . SendKeys , PiayKeys. , , , Microsoft Windows 98 2000 Sendinput. Windows NT 4, Service Pack 3 ( ). Sendinput Microsoft Active Accessibility (MSAA) , keybd_event. Sendinput , . ( ), , . Tester'a. , Sendinput Outlook 2000.
. Visual Basic sendKeys , piayKeys , . , , , , SourceCode\Tester\TInputHlp -. Tinput, Tester C++ ++- (DLL). Tinput. PiayKeys VB-- DLL.
TWindow, Twindows TSystem . Visual Basic API- Windows. TNotify, . , , , , . , , , "" .
, 1. , SDK- , - . , . HCBT_CREATEWND, . , -, , WM_CREATE, . HCBT_CREATEWND . - .
computer-based training, .
, . , WM_CREATE . WM_SETTEXT. , , WM_SETTEXT. , () , WM_SETTEXT . : , Microsoft Internet Explorer, WM_SETTEXT .
, WM_SETTEXT ( WM_CREATE), , . WH_CALLWNDPROCRET. WM_CREATE, WM_SETTEXT. WM_DESTROY. WM_DESTROY, . . , , . , , WM_NCDESTROY.
"" "" WM_SETTEXT , , WM_S-. (state machine), . , . WM_ST- , . , TNotify- , "", NOTEPAD.EXE, , NOTEPAD.EXE . , "--" , "" . , TNotify-; .
Tester Visual Basic , TNotify. , Tnotify, , checkNotification. , Visual Basic , , , TESTER.DLL.
, :
: - . , DLL - TESTER.DLL, Visual Basic. , Visual Basic- , .
, 16- Windows-, , API- setTimer. , . , TNotify, , , .
, , , TNotify. , , WM_TIMER , checkNotification, . , TSystem. Pause, DoEvents ( TSystem. Pause) . , DoEvents TSystem.pause , CheckNotification.
, , , Tester. 13-3 - TNOTIFYHLP.CPP. Tester'a TNOTIFY. BAS , , TNOTIFY.CLS. TNotify , TNotify , , . (.HOOKDATA), . , , " ".
13-3.TNOTIFY.
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"Debugging Applications" (Microsoft Press)
Copyright (c) 1997-2000 John Robbins All rights reserved.
TNotifyHlp.dll
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
#include <tchar.h>
#include <windows.h>
#include "TNotifyHlp.h"
/*///////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////*/
//
static const int TOTAL_NOTIFY_SLOTS = 5;
//
static const LPCTSTR k_MUTEX_NAME = _T ( "TNotifyHlp_Mutex");
//
static const int k_WAITLIMIT = 5000;
// TRACE
// BugslayerUtil.DLL
// .
#ifdef _DEBUG
#define TRACE ::OutputDebugString
#else
#define TRACE (void)0
#endif
/*//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////*/
//
typedef struct tagJTNOTIFYITEM
{
// PID ,
DWORD dwOwnerPID ;
//
int iNotifyType;
//
int iSearchType;
// HWND-
HWND hWndCreate ;
//
BOOL bDestroy ;
//
TCHAR szTitle [ _ ];
} TNOTIFYITEM, * PTNOTIFYITEM;
/*///////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////*/
// ,
// .
// HINSTANCE- .
// DLL.
static HINSTANCE gjnlnst = NULL;
// , g_NotifyData
static HANDLE g_hMutex = NULL;
// .
// , . .
// .
static HHOOK g_hHook = NULL;
// , ,
// , ,
static int g_iThisProcess!tems = 0;
/*/////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////*/
//
LRESULT CALLBACK CallWndRetProcHook ( int nCode ,
WPARAM wParam,
LPARAM IParam );
//
static LONG _stdcall CheckNotifyltem ( HANDLE hltem, BOOL bCreate);
/*////////////////////////////////////////////////////////////////
()
/////////////////////////////////////////////////////////////////*/
#pragma data_seg ( ". HOOKDATA")
//
static TNOTIFYITEM g_shared_NotifyData [ TOTAL_NOTIFY_SLOTS ] =
{
{ 0,0 , 0, NULL, 0, '\0' },
{ 0, 0, 0, NULL, 0, '\0' },
{ 0, 0, 0, NULL, 0, '\0' },
{ 0, 0, 0, NULL, 0, '\0' },
{ 0, 0, 0, NULL, 0, '\0' }
};
//
static int g_shared_iUsedSlots = 0;
#pragma data_seg ()
/*////////////////////////////////////////////////////
///////////////////////////////////////////////////*/
extern "C" BOOL WINAPI DllMain ( HINSTANCE hlnst ,
DWORD dwReason ,
LPVOID /*lpReserved*/)
{
#ifdef _DEBUG
BOOL bCHRet;
#endif
BOOL bRet = TRUE;
switch ( dwReason)
{
case DLL_PROCESS_ATTACH :
// .
g_hlnst = hlnst;
// .
DisableThreadLibraryCalls ( g_hlnst);
// . ,
// .
g_hMutex = CreateMutex ( NULL, FALSE, k_MUTEX_NAME);
if ( NULL == g_hMutex)
{
TRACE ( _T ( "Unable to create the mutex!\n"));
// ,
// , DLL.
bRet = FALSE; }
break;
case DLL_PROCESS_DETACH :
// , -
// . , ,
// (orphan) .
if (0 != g_iThisProcess!tems)
{
DWORD dwProcID = GetCurrentProcessId ();
// ,
// DLL_PROCESS_DETACH
// .
// .
for ( int i = 0; i < TOTAL_NOTIFY_SLOTS; i++)
(
if ( g_shared_NotifyData[i].dwOwnerPID == dwProcID)
{
#ifdef __DEBUG
TCHAR szBuff[ 50 ] ;
wsprintf ( szBuff,
_T( "DLL_PROCESS_DETACH removing : #%d\n"),
i);
TRACE ( szBuff);
#endif
// . RemoveNotifyTitle ( (HANDLE)i);
}
}
}
// .
#ifdef _DEBUG
bCHRet =
#endif
CloseHandle ( g_hMutex);
#ifdef _DEBUG
if ( FALSE == bCHRet)
{
TRACE ( "!!!!!!!!!!!!!!!!!!!!!!!!\n");
TRACE { "CloseHandle(gJiMutex) "
"failed!!!!!!!!!!!!!!!!!!\n");
TRACE ( "!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
#endif
break;
default :
break;
}
return ( bRet);
}
HANDLE TNOTIFYHLP_DLLINTERFACE _stdcall
AddNotifyTitle ( int iNotifyType,
int iSearchType,
LPCTSTR szString )
{
// , ,
if ( ( iNotifyType < ANTN_DESTROYWINDOW ) ||
( iNotifyType > ANTN_CREATEANDDESTROY ) )
{
TRACE ( "AddNotify Title : iNotifyType is out of range!\n");
return ( INVALID_HANDLE_VALUE);
}
// , ,
if ( ( iSearchType < ANTS_EXACTMATCH ) ||
( iSearchType > ANTS_ANYLOCMATCH) )
{
TRACE ( "AddNotify Title : iSearchType is out of range!\n");
return ( INVALID_HANDLE_VALUE);
}
// , ,
if ( TRUE == IsBadStringPtr ( szString, MAX_PATH))
{
TRACE ( "AddNotify Title : szString is invalid!\n");
return ( INVALID_HANDLE_VALUE);
}
// .
DWORD dwRet = WaitForSingleObject ( g_hMutex, k_WAITLIMIT);
if ( WAIT_TIMEOUT == dwRet)
{
TRACE ( _T( "AddNotifyTitle : Wait on mutex timed out!!\n"));
return ( INVALID_HANDLE_VALUE);
}
// , .
if ( TOTAL_NOTIFY_SLOTS == g_shared_iUsedSlots)
{
ReleaseMutex ( g_hMutex);
return ( INVALID_HANDLE_VALUE);
}
// ,
for ( int i = 0; i < TOTAL_NOTIFY_SLOTS; i++)
{
if ( _T ( '\0') == g_shared_NotifyData[ i ].szTitle[ 0 ])
{
break;
}
}
// .
g_shared_NotifyData[ i ].dwOwnerPID = GetCurrentProcessId ();
g_shared_NotifyData[ i ].iNotifyType = iNotifyType;
g__shared_NotifyData[ i ].iSearchType = iSearchType;
Istrcpy ( g_shared__Notif yData [ i J.szTitle, szString);
//
. g_shared_iUsedSlots++;
// .
g_iThis Process Items++;
TRACE ( "AddNotifyTitle - Added a new item!\n");
ReleaseMutex ( g_hMutex);
// , .
if ( NULL = g_hHook)
{
g_hHook = SetWindowsHookEx ( WH_CALLWNDPROCRET ,
CallWndRetProcHook, g_hlnst , 0 );
#ifdef _DEBUG
if ( NULL == g_hHook)
{
char szBuff[ 50 ];
wsprintf ( szBuff,
_T ( "SetWindowsHookEx failed!!!! (Ox%08X)\n"), GetLastError ());
TRACE ( szBuff);
}
#endif
}
return ( (HANDLE)!);
}
void TNOTIFYHLP_DLLINTERFACE _stdcall
RemoveNotifyTitle ( HANDLE hltem)
{
// .
int i = (int)hltem;
if ( ( i < 0) || ( i > TOTAL_NOTIFY_SLOTS))
{
TRACE ( _T ( "RemoveNotifyTitle : Invalid handle!\n"));
return;
}
// .
DWORD dwRet = WaitForSingleObject ( g_hMutex, k_WAITLIMIT);
if ( WAIT_TIMEOUT == dwRet)
{
TRACE ( _T ( "RemoveNotifyTitle : Wait on mutex timed out!\n"));
return;
}
if ( 0 = g_shared_iUsedSlots)
{
TRACE ( _T ( "RemoveNotifyTitle : Attempting to remove when "
"no notification handles are set!\n"));
ReleaseMutex ( g_hMutex);
return;
}
// -, ,
// NotifyData, .
//
// , .
if ( 0 == g_shared_NotifyData[ i ].dwOwnerPID)
{
TRACE ( "RemoveNotifyTitle : Attempting to double remove!\n");
ReleaseMutex ( g_hMutex);
return;
}
// .
g_shared_NotifyData[ i ].dwOwnerPID =0;
g_shared_NotifyData[ i ].iNotifyType = 0;
g_share.d_NotifyData [ i ] .hWndCreate = NULL;
g_shared_NotifyData[ i ].bDestroy = FALSE;
g_shared_NotifyData[ i ].iSearchType = 0;
g_shared_NotifyData[ i ].szTitle[ 0 ] = _T ( '\0');
// .
g_shared_iUsedSlots- -;
// .
g_iThisProcessItems- -;
TRACE ( _ ( "RemoveNotifyTitle - Removed an item!\n"));
ReleaseMutex ( g_hMutex);
// ,
// .
if ( ( 0 == g_iThisProcess!tems) && ( NULL != g_hHook))
{
if ( FALSE = UnhookWindowsHookEx ( g_hHook))
{
TRACE ( _T ( "UnhookWindowsHookEx failed!\n"));
}
g_hHook = NULL;
}
} HWND TNOTIFYHLP_DLLINTERFACE _stdcall
CheckNotifyCreateTitle ( HANDLE hltem)
{
return ( (HWND)CheckNotifyltem ( hltem, TRUE));
}
BOOL TNOTIFYHLP_DLLINTERFACE _stdcall
CheckNotifyDestroyTitle ( HANDLE hltem)
{
return ( (BOOL)CheckNotifyltem ( hltem, FALSE));
}
/*///////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////*/
static LONG _stdcall CheckNotifyltem { HANDLE hltem, BOOL bCreate)
{
// .
int i = (int)hltem;
if ( ( i < 0) || ( i > TOTAL_NOTIFY_SLOTS))
{
TRACE ( _T ( "CheckNotifyltem : Invalid handle!\n"));
return ( NULL);
}
LONG IRet = 0;
// .
DWORD dwRet = WaitForSingleObject ( g_hMutex, k_WAITLIMIT);
if ( WAIT_TIMEOUT == dwRet)
{
TRACE ( _T ( "CheckNotifyltem : Wait on mutex timed out!\n"));
return ( NULL);
}
// , .
if ( 0 = g_shared_iUsedSlots)
{
ReleaseMutex ( g_hMutex);
return ( NULL);
}
// ,
if ( TRUE == bCreate)
{
// HWND- NULL,
// .
if ( NULL != g_shared_NotifyData[ i ].hWndCreate)
{
IRet = (LONG)g_shared_NotifyData[ i ].hWndCreate;
g_shared_NotifyData[ i ].hWndCreate = NULL;
}
}
else
{
if ( FALSE != g_shared_NotifyData[ i ].bDestroy)
{
IRet = TRUE;
g_shared_NotifyData[ i ].bDestroy = FALSE;
}
}
ReleaseMutex ( g_hMutex);
return ( IRet);
}
static void _stdcall CheckTableMatch ( int iNotifyType,
HWND hWnd ,
LPCTSTR szTitle ) {
// .
DWORD dwRet = WaitForSingleObject ( g__hMutex, k_WAITLIMIT);
if ( WAIT_TIMEOUT == dwRet)
{
TRACE ( _T ( "CheckTableMatch : Wait on mutex timed out!\n"));
return;
}
// , .
if ( 0 == g_shared_iUsedSlots)
{
ReleaseMutex ( g_hMutex);
TRACE { _T ( "CheckTableMatch called on an empty table!\n"));
return;
}
// .
for ( int i = 0; i < TOTAL_NOTIFY_SLOTS; i++)
{
// -
// ?
if- ( ( _ ( '\0') != g_shared_NotifyData[ i ].szTitle[ 0 ]) &&
( g__shared_NotifyData[ i ].iNotifyType & iNotifyType ) )
{
BOOL bMatch = FALSE;
// .
switch ( g_shared_NotifyData[ i ].iSearchType)
{
case ANTS_EXACTMATCH :
// ,
if ( 0 = Istrcmp ( g_shared_NotifyData[i].szTitle,
szTitle ))
{
bMatch = TRUE;
}
break;
case ANTS_BEGINMATCH :
if ( 0 ==
_tcsnccmp ( g_shared_NotifyData[i].szTitle,
szTitle , strlen(g_shared_NotifyData[i].szTitle)))
{
bMatch = TRUE;
}
break; case ANTS_ANYLOCMATCH :
if ( NULL != _tcsstr ( szTitle
g_shared_NotifyData[i].szTitle))
{
bMatch = TRUE;
}
break;
default :
TRACE ( _T ( "CheckTableMatch invalid "\ "search type!!!\n"));
ReleaseMutex ( g_hMutex);
return;
break;
}
// ?
if ( TRUE = bMatch)
{
// , "1"
// .
if ( ANTN_DESTROYWINDOW == iNotifyType)
{
g_shared_NotifyData[ i ].bDestroy = TRUE;
}
else
{
// , HWND.
g_shared_NotifyData[ i ].hWndCreate - hWnd;
}
}
}
}
ReleaseMutex ( g_hMutex);
}
LRESULT CALLBACK CallWndRetProcHook ( int nCode ,
WPARAM wParam,
LPARAM IParam )
{
//
TCHAR szBuff[ _ ];
// ,
// - .
LRESULT IRet = CallNextHookEx ( gJnHook, nCode, wParam, IParam);
// The docs say never to mess around with a negative code, so I don't.
//
// , .
if ( nCode < 0)
{
return ( IRet);
}
// . ( )
// ?
// ole-
// /?
PCWPRETSTRUCT pMsg = (PCWPRETSTRUCT)IParam;
// ,
LONG IStyle = GetWindowLong ( pMsg->hwnd, GWL_STYLE);
if ( WS_CAPTION != ( IStyle & WS_CAPTION)) {
return ( IRet);
}
// WM_DESTROY ,
// .
// .
if ( WM_DESTROY == pMsg->message)
{
if (0 != GetWindowText ( pMsg->hwnd, szBuff, MAX_PATH))
{
CheckTableMatch ( ANTN_DESTROYWINDOW, pMsg->hwnd, szBuff);
}
return ( IRet);
}
// , .
// . ,
// WM_INITDIALOG.
if ( 0 == GetClassName ( pMsg->hwnd, szBuff, MAX_PATH))
{
#iifdef _DEBUG
TCHAR szBuff[ 50 ];
wsprintf ( szBuff ,
_T ( "GetClassName failed for HWND : 0x%08X\n"),
pMsg->hwnd ) ;
TRACE ( szBuff);
#endif
//He ,
return ( IRet);
}
if ( 0 == Istrcmpi ( szBuff, _T ( "#32770")))
{
// , ,
// - WM_INITDIALOG.
if ( WM_INITDIALOG == pMsg->message)
{
// .
if (0 != GetWindowText ( pMsg->hwnd, szBuff, MAX_PATH))
{
CheckTableMatch ( ANTN_CREATEWINDOW,
pMsg->hwnd ,
szBuff );
}
}
return ( IRet);
}
//
// .
// , ,
if ( WM_CREATE == pMsg->message)
{
//
// WM_CREATE.
// WM_SETTEXT, .
if (0 != GetWindowText ( pMsg->hwnd, szBuff, MAX_PATH))
{
CheckTableMatch ( ANTN_CREATEWINDOW,
pMsg->hwnd ,
szBuff );
}
}
else if ( WM_SETTEXT = pMsg->message)
{
// WM_SETTEXT,
// . ,
// , Internet Explorer, WM_SETTEXT
// ' .
// , WM_SETTEXT ,
//
// ,
// WM_SETTEXT.
if ( NULL != pMsg->lParam)
{
CheckTableMatch ( ANTN_CREATEWINDOW ,
pMsg->hwnd ,
(LPCTSTR)pMsg->lParam );
}
}
return ( IRet);
}
TNotify , - , . , , . Microsoft Visual C++, . SoftlCE. . , printf- . DBGVIEW OutputDebugString , , .
Tester'a, Windows 98. - Windows NT 4 Windows 2000, Windows 98 TWindows. HWND , Add, iswindow. , iswindow BOOL. , TRUE , FALSE . , 1 = iswindow (hWndT), , , . , . "", .
, Tester : . , Tester'a, , , . , :
(UI) . (Tester), , . , , Tester, , ( ).
, Tester , , . , . , , , , (QA-) QA- .
10.11.2021 - 12:37: - Personalias -> WHO IS WHO - - _. 10.11.2021 - 12:36: - Conscience -> . ? - _. 10.11.2021 - 12:36: , , - Upbringing, Inlightening, Education -> ... - _. 10.11.2021 - 12:35: - Ecology -> - _. 10.11.2021 - 12:34: , - War, Politics and Science -> - _. 10.11.2021 - 12:34: , - War, Politics and Science -> . - _. 10.11.2021 - 12:34: , , - Upbringing, Inlightening, Education -> , - _. 10.11.2021 - 09:18: - New Technologies -> , 5G- - _. 10.11.2021 - 09:18: - Ecology -> - _. 10.11.2021 - 09:16: - Ecology -> - _. 10.11.2021 - 09:15: , , - Upbringing, Inlightening, Education -> - _. 10.11.2021 - 09:13: , , - Upbringing, Inlightening, Education -> - _. |