|
|
Ïðåäâàðèòåëüíûå çàìå÷àíèÿÊàê è â ñëó÷àå ñ Microsoft Speech API 4.0 ( ñì. ñîîòâåòñòâóþùóþ ñòàòüþ), äëÿ âçàèìîäåéñòâèÿ ñ êîìïîíåíòàìè Microsoft Speech API 5.1 (MS SAPI 5.1) ìû âîñïîëüçóåìñÿ ôóíêöèÿìè áèáëèîòåêè DispHelper. Êðîìå óæå èçâåñòíûõ íàì ôóíêöèé dhCallMethod, dhGetValue è dhPutValue, äëÿ ðàáîòû ñ êîëëåêöèÿìè îáúåêòîâ, âîçâðàùàåìûõ íåêîòîðûìè ìåòîäàìè êîìïîíåíòîâ SAPI 5.1, íàì ïîòðåáóþòñÿ ôóíêöèÿ dhPutRef è íàáîð ìàêðîñîâ FOR_EACH. Ýòè ìàêðîñû îáúÿâëåíû â ôàéëå disphelper.bi. Ìàêðîñû FOR_EACH îòëè÷àþòñÿ äðóã îò äðóãà êîëè÷åñòâîì àðãóìåíòîâ, ÷òî ñîîòâåòñòâóþùèì îáðàçîì îòðàæàåòñÿ â èìåíè ìàêðîñà: FOR_EACH0, FOR_EACH1, FOR_EACH2,.. FOR_EACH9. Âñå ðàçíîâèäíîñòè ýòîãî ìàêðîñà ïîçâîëÿþò âûçâàòü ìåòîä, âîçâðàùàþùèé êîëëåêöèþ îáúåêòîâ, à çàòåì âûïîëíèòü îïðåäåëåííûå äåéñòâèÿ ñ êàæäûì èç îáúåêòîâ êîëëåêöèè (íàïðèìåð, âûçâàòü ìåòîä, ïîëó÷èòü èëè ïðèñâîèòü çíà÷åíèå ñâîéñòâó îáúåêòà).  âåðñèè 0.15b êîìïèëÿòîðà FreeBASIC â ôàéëå disphelper.bi ìàêðîñ FOR_EACH ñîäåðæèò îøèáêó, èç-çà êîòîðîé íåëüçÿ áûëî óñïåøíî ñêîìïèëèðîâàòü ïðîãðàììó. Äëÿ òîãî ÷òîáû îáîéòè ýòó îøèáêó, â íà÷àëî èñõîäíîãî êîäà, ãäå èñïîëüçóåòñÿ ìàêðîñ FOR_EACH) ïîñëå ñòðîêè #include "disphelper/disphelper.bi"ñëåäóåò ïîìåñòèòü òàêîé ôðàãìåíò: #ifdef FOR_EACH0 #undef FOR_EACH0 #define FOR_EACH0(objName, pDisp, szMember) _ scope :_ dim as IEnumVARIANT ptr xx_pEnum_xx = NULL :_ DISPATCH_OBJ(objName) :_ if (SUCCEEDED(dhEnumBegin(@xx_pEnum_xx, pDisp, szMember))) then :_ do while(dhEnumNextObject(xx_pEnum_xx, @objName) = NOERROR) #endif Ñóòü îøèáêè â òîì, ÷òî âìåñòî êëþ÷åâîãî ñëîâà Scope èñïîëüçîâàíî "escope", à ïðèâåäåííûé ôðàãìåíò èñïðàâëÿåò ýòó ñèòóàöèþ. Àíàëîãè÷íàÿ îøèáêà ïðèñóòñòâóåò âî âñåõ ðåàëèçàöèÿõ ìàêðîñà FOR_EACH.  âåðñèè 0.16b êîìïèëÿòîðà FreeBASIC ýòà îøèáêà óñòðàíåíà. Îäíàêî òå, êòî ðåøèë ïåðåéòè îò âåðñèè 0.15b ê âåðñèè 0.16b, äîëæíû îáðàòèòü âíèìàíèå íà òî, ÷òî â íîâîé âåðñèè ïî-èíîìó îáðàáàòûâàåòñÿ óíàðíûé îïåðàòîð NOT. Íàïðèìåð, ïðåäïîëîæèì, ÷òî ôóíêöèÿ MyFunc() âîçâðàùàåò ëîãè÷åñêîå çíà÷åíèå TRUE èëè FALSE. Äëÿ êîìïèëÿòîðà âåðñèè 0.15b êîððåêòíûì áûëî òàêîå âûðàæåíèå: IF NOT MyFunc() THEN MessageBox (NULL, "Ôóíêöèÿ âåðíóëà FALSE.", "Îò÷åò", 0) ELSE MessageBox (NULL, "Ôóíêöèÿ âåðíóëà TRUE.", "Îò÷åò", 0) END IF  ïðèëîæåíèè, ñîáðàííîì ïðè ïîìîùè êîìïèëÿòîðà âåðñèè 0.16b, âûøåóêàçàííàÿ êîíñòðóêöèÿ áóäåò ðàáîòàòü ñ îøèáêîé. Äëÿ ïðàâèëüíîé ðàáîòû ýòîãî êîäà íåîáõîäèìî íåïîñðåäñòâåííî ñðàâíèâàòü ðåçóëüòàò ðàáîòû ôóíêöèè MyFunc() ñ êîíñòàíòàìè TRUE èëè FALSE. Íàïðèìåð: IF FALSE = MyFunc() THEN MessageBox (NULL, "Ôóíêöèÿ âåðíóëà FALSE.", "Îò÷åò", 0) ELSE MessageBox (NULL, "Ôóíêöèÿ âåðíóëà TRUE.", "Îò÷åò", 0) END IF Ðàáîòà ñ îáúåêòîì SpVoiceÍàèáîëåå ïîëíóþ èíôîðìàöèþ î ìåòîäàõ è ñâîéñòâàõ îáúåêòîâ OLE àâòîìàòèçàöèè, âõîäÿùèõ â ñîñòàâ MS SAPI 5.1, ìîæíî íàéòè â äîêóìåíòàöèè, ïðèëàãàåìîé ê MS SAPI SDK 5.1 (ðàçäåë Automation). Òàì æå ïðèâîäÿòñÿ ðàçëè÷íûå ïðèìåðû èñõîäíîãî êîäà äëÿ ñðåäû Visual Basic. Ïàêåò MS Speech SDK, à òàêæå äîïîëíèòåëüíûå ãîëîñà ìîæíî çàãðóçèòü ñî ñòðàíèöû ïîðòàëà Microsoft (ñì. ðàçäåë â êîíöå ñòàòüè). Îñíîâíûì îáúåêòîì, ðåàëèçóþùèì ñèíòåç ðå÷è ïî òåêñòó, ÿâëÿåòñÿ SpVoice. Ñòðîãî ãîâîðÿ, ïðè èñïîëüçîâàíèè ôóíêöèé DispHelper íå èìååò çíà÷åíèÿ íàçâàíèå îáúåêòà, ïîòîìó ÷òî â êîäå ïðîãðàììû âñå îáúåêòû ÿâëÿþòñÿ óêàçàòåëÿìè íà èíòåðôåéñ IDispatch. Îäíàêî äëÿ óäîáñòâà ìû îñòàâèì çà îáúåêòàìè òå èìåíà, êîòîðûå íàçíà÷åíû èì â äîêóìåíòàöèè ê MS SAPI 5.1. Ïðè èñïîëüçîâàíèè ôóíêöèé DispHelper íåîáõîäèìî çíàòü íàçâàíèÿ ìåòîäîâ (methods) è ñâîéñòâ (properties) èíòåðåñóþùåãî íàñ îáúåêòà. Âîò ïåðå÷åíü ìåòîäîâ è ñâîéñòâ îáúåêòà SpVoice, êîòîðûå áóäóò èñïîëüçîâàíû â íèæåñëåäóþùèõ ïðèìåðàõ:
Ñëåäóåò îáðàòèòü âíèìàíèå íà òî, ÷òî ìåòîä .GetVoices îáúåêòà SpVoice ïîëó÷àåò íåîáõîäèìóþ èíôîðìàöèþ îá óñòàíîâëåííûõ ãîëîñàõ ("äâèæêàõ" èç ñèñòåìíîãî ðååñòðà (âåòêà "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens"). Îäíàêî ðååñòð íå âñåãäà ñîäåðæèò êîððåêòíóþ èíôîðìàöèþ. Íàïðèìåð, â íåì ìîãóò îêàçàòüñÿ "áèòûå" âåòêè, îñòàâëåííûå ðàíåå óñòàíîâëåííûìè SAPI5-ñèíòåçàòîðàìè è íå óäàëåííûå èìè ïðè äåèíñòàëëÿöèè. Åñëè âûáðàòü òàêîé "áèòûé" ãîëîñ â êà÷åñòâå àêòèâíîãî, òî âîçíèêíåò îøèáêà (â òîì ÷èñëå è â Ïàíåëè óïðàâëåíèÿ -> Ðå÷ü). Èòàê, òåïåðü óæå ìîæíî ïðèñòóïàòü ê íàïèñàíèþ êîäà. Ìû ñîáèðàåìñÿ èñïîëüçîâàòü ãîëîñàMS SAPI 5.1 äëÿ ñèíòåçà ðå÷è â íàøåì ïðèëîæåíèè íà FreeBASIC. Äëÿ ýòîãî íåîáõîäèìî âûïîëíèòü íåñêîëüêî ïîñëåäîâàòåëüíûõ äåéñòâèé. Ïåðâûì äåëîì, ïðè ïîìîùè ôóíêöèè DHCreateObject ìû çàãðóçèì â ïàìÿòü îáúåêò SpVoice, çàðåãèñòðèðîâàííûé â ñèñòåìå êàê "Sapi.SpVoice":
DIM object IDispatch ptr
IF FAILED(dhCreateObject ("Sapi.SpVoice", NULL, @Object)) THEN
'... îáðàáîòêà îøèáêè
END IF
' ... íîðìàëüíàÿ ðàáîòà
Çàòåì ïðè ïîìîùè ìåòîäà .GetVoices ìîæíî ïîëó÷èòü êîëëåêöèþ èìåþùèõñÿ ãîëîñîâ è, ïåðåáðàâ èõ ïðè ïîìîùè ìàêðîñà FOR_EACH0, çàïîëíèòü íàçâàíèÿìè ýòèõ ãîëîñîâ, íàïðèìåð, âûïàäàþùèé ñïèñîê. Ýòî äàñò ïîëüçîâàòåëþ âîçìîæíîñòü ñàìîñòîÿòåëüíî âûáðàòü íóæíûé ãîëîñ èç ñïèñêà.
DIM szDescription AS WSTRING PTR
FOR_EACH0(spVoice, Object, ".GetVoices")
' Ïîëó÷àåì ñòðîêó îïèñàíèÿ î÷åðåäíîãî ãîëîñà
dhGetValue("%S", @szDescription, spVoice, ".GetDescription")
' Ïîìåùàåì ñòðîêó ñ îïèñàíèåì ãîëîñà â êîìáèíèðîâàííûé ñïèñîê
SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
NEXT_(spvoice)
dhFreeString(szDescription)
Ñëåäóþùèé ôðàãìåíò êîäà ïîêàçûâàåò, êàê óñòàíîâèòü âûáðàííûé ãîëîñ â êà÷åñòâå àêòèâíîãî (ñâîéñòâî .Voice îáúåêòà SpVoice). Çäåñü ïåðåìåííàÿ Index ñîäåðæèò íîìåð âûáðàííîãî ãîëîñà:
DHGetValue ("%o", @spVoices, object, ".GetVoices")
DHGetValue ("%o", @spVoice, spVoices, ".Item(%u)", Index)
dhPutRef(Object, ".Voice = %o", spVoice)
Ìåòîä .GetVoices îáúåêòà SpVoice ìîæåò â êà÷åñòâå àðãóìåíòà ïðèíèìàòü ñòðîêó, ñîäåðæàùóþ ïàðàìåòðû îòáîðà ãîëîñîâ èç îáùåãî ñïèñêà. Íàïðèìåð, äëÿ òîãî ÷òîáû îòîáðàòü òîëüêî òå ãîëîñà, êîòîðûå ïðåäíàçíà÷åíû äëÿ ñèíòåçà ðóññêîé ðå÷è, íóæíî ïåðåäàòü ñòðîêó "Language=419". Ðàçóìååòñÿ, â ýòîì ñëó÷àå íóæíî èñïîëüçîâàòü ìàêðîñ FOR_EACH1:
DIM szDescription AS WSTRING PTR
FOR_EACH1(spVoice, Object, ".GetVoices(%s)", "Language=419")
dhGetValue("%S", @szDescription, spVoice, ".GetDescription")
SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
NEXT_(spvoice)
dhFreeString(szDescription)
Ñîîòâåòñòâóþùèå èçìåíåíèÿ íóæíî âíåñòè è âî ôðàãìåíò êîäà, â êîòîðîì óñòàíàâëèâàåòñÿ àêòèâíûé ãîëîñ:
DHGetValue ("%o", @spVoices, object, ".GetVoices(%s)", "Language=419")
DHGetValue ("%o", @spVoice, spVoices, ".Item(%u)", Index)
dhPutRef(Object, ".Voice = %o", spVoice)
Àíàëîãè÷íûì îáðàçîì ìû ìîæåì ïðåäîñòàâèòü ïîëüçîâàòåëþ âîçìîæíîñòü âûáðàòü çâóêîâîå óñòðîéñòâî, ÷åðåç êîòîðîå áóäåò çâó÷àòü ñèíòåçèðîâàííàÿ ðå÷ü. Ýòî áûâàåò íåîáõîäèìî, êîãäà òðåáóåòñÿ ðàçäåëèòü çâóêîâîé è ðå÷åâîé ïîòîêè ìåæäó äâóìÿ è áîëåå çâóêîâûìè êàðòàìè èëè, íàïðèìåð, ìåæäó çâóêîâîé êàðòîé è ãîëîñîâûì ìîäåìîì. Ïðèìåð òàêîãî ðåøåíèÿ ïðèâåäåí â èñõîäíûõ êîäàõ äåìîíñòðàöèîííîé ïðîãðàììû. Ïîñëåäíèé øàã -- ýòî íåïîñðåäñòâåííûé ñèíòåç ðå÷è. Äëÿ ýòîãî äîñòàòî÷íî âûçâàòü ìåòîä .Speak, ïåðåäàâ â êà÷åñòâå àðãóìåíòà ñòðîêó òåêñòà, êîòîðûé íóæíî îçâó÷èòü. dhCallMethod(Object, ".Speak(%S)", Phrase) Ïðèìåð èñõîäíîãî êîäà êà÷åñòâå ïðèìåðà íèæå ïðèâåäåí èñõîäíûé êîä ïðèëîæåíèÿ Windows, êîòîðîå îòîáðàæàåò íà ýêðàíå äèàëîãîâîå îêíî ñî ñïèñêîì óñòàíîâëåííûõ â ñèñòåìå ãîëîñîâ MS SAPI 5.1 è ñïèñêîì äîñòóïíûõ çâóêîâûõ óñòðîéñòâ. Êðîìå òîãî, â äèàëîãå ïðèñóòñòâóåò òåêñòîâîå ïîëå, â êîòîðîì ïîëüçîâàòåëü ìîæåò íàáðàòü òåêñò. Ïðè íàæàòèè êëàâèøè Enter èëè ïðè ùåë÷êå ïî êíîïêå "Speak" òåêñò èç ïîëÿ ðåäàêòèðîâàíèÿ áóäåò îçâó÷åí âûáðàííûì ãîëîñîì. Èñõîäíûé êîä ïðèëîæåíèÿ âêëþ÷àåò ñëåäóþùèå ôàéëû:
Ôàéë speech.bas
' speech.bas - Îñíîâíîé ôàéë ïðèëîæåíèÿ, äåìîíñòðèðóþùåãî èñïîëüçîâàíèå
' MS SAPI 5.1 â ïðîãðàììàõ íà FreeBASIC.
' Êîìïèëèðîâàòü: fbc.exe" -s gui speech.rc speech.bas sapi5.bas
option explicit
#define UNICODE
#include once "windows.bi"
#include "disphelper/disphelper.bi"
#include "sapi5.bi"
#include "resource.bi"
DECLARE FUNCTION DlgProc (byval hwnd as HWND, byval umsg as UINT, byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
DIM SHARED as IDispatch ptr tts = NULL
dhInitialize( TRUE )
dhToggleExceptions( TRUE )
DialogBoxParam( GetModuleHandle( NULL), cptr(LPCSTR, IDD_DLG1), NULL, @DlgProc, NULL )
SAFE_RELEASE( tts)
dhUninitialize( TRUE )
END
' Program end
FUNCTION DlgProc (byval hwnd as HWND, byval umsg as UINT, byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
DIM as long id, event
SELECT CASE uMsg
CASE WM_INITDIALOG
IF TRUE <> SAPI5_Initialize(tts) THEN
EndDialog( hwnd, 0 )
Return TRUE
END IF
' Çàïîëíÿåì ñïèñîê ãîëîñîâ
SAPI5_GetVoices(tts, GetDlgItem(hWnd, IDC_VOICES_LIST))
SAPI5_SelectVoice (tts, 0)
SAPI5_SetSpeed (tts, 5)
SAPI5_SetVolume(tts, 100)
' Çàïîëíÿåì ñïèñîê àóäèîóñòðîéñòâ
SAPI5_GetAudioOutputs(tts, GetDlgItem(hWnd, IDC_AUDIOOUTPUTS_LIST))
SAPI5_SelectAudioOutput(tts, 0)
CASE WM_CLOSE
EndDialog( hwnd, 0 )
CASE WM_COMMAND
id = loword( wParam )
event = hiword( wParam )
SELECT CASE id
CASE IDOK
scope
DIM szBuf as WSTRING * 1024
GetDlgItemText(hWnd, IDC_TEXT_TO_SPEAK, szBuf, 1024)
SAPI5_Speak (tts, @szBuf)
END Scope
CASE IDCANCEL
EndDialog( hwnd, 0 )
CASE IDC_VOICES_LIST:
IF CBN_SELCHANGE = event THEN
SAPI5_SelectVoice (tts, SendDlgItemMessage (hWnd, Id, CB_GETCURSEL, 0, 0))
END IF
CASE IDC_AUDIOOUTPUTS_LIST:
IF CBN_SELCHANGE = event THEN
SAPI5_SelectAudioOutput(tts, SendDlgItemMessage (hWnd, Id, CB_GETCURSEL, 0, 0))
End If
END SELECT
CASE ELSE
return FALSE
END SELECT
return TRUE
END FUNCTION
Ôàéë speech.rc#include "resource.bi" IDD_DLG1 DIALOGEX 0,0,200,90 CAPTION "SAPI 5: Text-to-speech Example" FONT 8,"MS Sans Serif" STYLE 0x10CC0000 EXSTYLE 0x00000080 BEGIN LTEXT "Voice:", IDC_STATIC, 5, 5, 40, 9 COMBOBOX IDC_VOICES_LIST, 50, 5, 145, 10, WS_TABSTOP| CBS_DROPDOWNLIST | WS_VSCROLL LTEXT "Output:", IDC_STATIC, 5, 5+11, 40, 9 COMBOBOX IDC_AUDIOOUTPUTS_LIST , 50, 5+11, 145, 10, WS_TABSTOP| CBS_DROPDOWNLIST | WS_VSCROLL LTEXT "Text to speak:", IDC_STATIC, 5, 5+22, 100, 10 EDITTEXT IDC_TEXT_TO_SPEAK, 5, 5+33, 190, 10 DEFPUSHBUTTON "Speak", IDOK, 120, 5+55, 35, 10 PUSHBUTTON "Close", IDCANCEL, 120+37, 5+55, 35, 10 END Ôàéë resource.bi#define IDD_DLG1 1000 #define IDC_BTN1 1002 #define IDC_STATIC -1 #define IDC_BTNSPEAK 1001 #define IDC_VOICES_LIST 2001 #define IDC_AUDIOOUTPUTS_LIST 2002 #define IDC_TEXT_TO_SPEAK 2003 #endif Ôàéë sapi5.bas
option explicit
#define UNICODE
#include once "windows.bi"
#include "disphelper/disphelper.bi"
FUNCTION SAPI5_Initialize (byRef Object as IDispatch PTR) as BOOL
DIM as String ProgId = "Sapi.SpVoice"
DIM hr as HRESULT
IF FAILED(dhCreateObject (ProgId, NULL, @Object)) THEN return FALSE
return TRUE
END FUNCTION
SUB SAPI5_GetVoices (byRef object as IDispatch ptr,byval hCtrl as HWND)
DIM szDescription as WString ptr
SendMessage (hCtrl, CB_RESETCONTENT, 0, 0)
FOR_EACH0(spVoice, Object, ".GetVoices")
dhGetValue("%S", @szDescription, spVoice, ".GetDescription")
SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
NEXT_(spvoice)
SendMessage (hCtrl, CB_SETCURSEL, 0, 0)
dhFreeString(szDescription)
END SUB
SUB SAPI5_SelectVoice (byRef Object as IDispatch ptr , byVal Index as Integer)
DIM spVoices, spVoice as IDispatch ptr
DHGetValue ("%o", @spVoices, object, ".GetVoices")
DHGetValue ("%o", @spVoice, spVoices, ".Item(%u)", Index)
dhPutRef(Object, ".Voice = %o", spVoice)
END SUB
SUB SAPI5_GetAudioOutputs(byRef object as IDispatch ptr,byval hCtrl as HWND)
DIM szDescription as WString ptr
SendMessage (hCtrl, CB_RESETCONTENT, 0, 0)
FOR_EACH0(spAudioOutput, Object, ".GetAudioOutputs")
dhGetValue("%S", @szDescription, spAudioOutput, ".GetDescription")
SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
NEXT_(spAudioOutput)
SendMessage (hCtrl, CB_SETCURSEL, 0, 0)
dhFreeString(szDescription)
END SUB
SUB SAPI5_SelectAudioOutput(byRef Object as IDispatch ptr , byVal Index as Integer)
DIM spAudioOutputs, spAudioOutput as IDispatch ptr
DHGetValue ("%o", @spAudioOutputs, object, ".GetAudioOutputs")
DHGetValue ("%o", @spAudioOutput, spAudioOutputs, ".Item(%u)", Index)
dhPutRef(Object, ".AudioOutput= %o", spAudioOutput)
END SUB
SUB SAPI5_SetSpeed (byRef Object as IDispatch ptr , byVal Speed as Integer)
dhPutValue(Object, ".Rate=%d", Speed)
END SUB
SUB SAPI5_SetVolume(byRef Object as IDispatch ptr , byVal Volume as Integer)
IF Volume > 100 THEN VOLUME = 100
IF Volume < 0 THEN Volume=0
dhPutValue(Object, ".Volume=%u", Volume)
END SUB
SUB SAPI5_Speak (byRef Object as IDispatch ptr , byVal Phrase as WString PTR)
dhCallMethod(Object, ".Speak(%S)", Phrase)
END SUB
Ôàéë sapi5.bi#ifndef _SAPI5_BI #define _SAPI5_BI DECLARE FUNCTION SAPI5_Initialize (byRef Object as IDispatch PTR) as BOOL DECLARE SUB SAPI5_GetVoices (byRef Object as IDispatch ptr, byval hCtrl as HWND) DECLARE SUB SAPI5_SelectVoice (byRef Object as IDispatch ptr, byVal Index as Integer) DECLARE SUB SAPI5_GetAudioOutputs(byRef Object as IDispatch ptr, byval hCtrl as HWND) DECLARE SUB SAPI5_SelectAudioOutput(byRef Object as IDispatch ptr, byVal Index as Integer) DECLARE SUB SAPI5_SetSpeed(byRef Object as IDispatch ptr , byVal Speed as Integer) DECLARE SUB SAPI5_SetVolume(byRef Object as IDispatch ptr , byVal Volume as Integer) DECLARE SUB SAPI5_Speak (byRef Object as IDispatch ptr , byVal Phraseas as WString PTR) #endif Ññûëêè ïî òåìå
|
||||||||
|
Ðàñïðîñòðàíåíèå ìàòåðèàëîâ ñàéòà îçíà÷àåò, ÷òî ðàñïðîñòðàíèòåëü ïðèíÿë óñëîâèÿ ëèöåíçèîííîãî ñîãëàøåíèÿ. Èäåÿ è ðåàëèçàöèÿ: © Âëàäèìèð Äîâûäåíêîâ è Àíàòîëèé Êàìûíèí, 2004-2026 | |||||||||
Ñîöèàëüíûå ñåòè