Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම
ජාලයේ IP-PBX Asterisk සහ CRM Bitrix24 ඒකාබද්ධ කිරීම සඳහා විවිධ විකල්ප ඇත, නමුත් අපි තවමත් අපේම ලිවීමට තීරණය කළෙමු.

ක්රියාකාරිත්වය අනුව, සෑම දෙයක්ම සම්මත වේ:

  • Bitrix24 හි සේවාලාභියෙකුගේ දුරකථන අංකය සහිත සබැඳියක් ක්ලික් කිරීමෙන්, Asterisk සේවාදායකයාගේ දුරකථන අංකය සමඟ ක්ලික් කිරීම සිදු කළ පරිශීලකයාගේ අභ්‍යන්තර අංකය සම්බන්ධ කරයි. Bitrix24 හි, ඇමතුමේ වාර්තාවක් පටිගත කර ඇති අතර, ඇමතුම අවසානයේ, සංවාදයේ පටිගත කිරීමක් ඉහළට ඇද දමනු ලැබේ.
  • Asterisk හට පිටතින් ඇමතුමක් ලැබේ - Bitrix24 අතුරුමුහුණතෙහි අපි මෙම ඇමතුම පැමිණි අංකයට සේවකයාට සේවාදායක කාඩ්පත පෙන්වමු.
    එවැනි සේවාදායකයෙක් නොමැති නම්, අපි නව නායකත්වයක් නිර්මාණය කිරීම සඳහා කාඩ්පත විවෘත කරන්නෙමු.
    ඇමතුම අවසන් වූ වහාම, අපි මෙය කාඩ්පතෙහි පිළිබිඹු කර සංවාදයේ පටිගත කිරීමක් අදින්නෙමු.

කප්පාදුවට පහළින් මම ඔබට සියල්ල සකසා ගන්නේ කෙසේද සහ ඔබට github වෙත සබැඳියක් ලබා දෙන්නේ කෙසේදැයි ඔබට කියමි - ඔව්, ඔව්, එය ගෙන එය භාවිතා කරන්න!

සාමාන්ය විස්තරය

අපි අපගේ ඒකාබද්ධතාවය CallMe ලෙස හැඳින්වුවෙමු. CallMe යනු PHP වලින් ලියා ඇති කුඩා වෙබ් යෙදුමකි.

භාවිතා කරන තාක්ෂණයන් සහ සේවාවන්

  • PHP 5.6
  • PHP AMI පුස්තකාලය
  • සංයුක්තය
  • Nginx + php-fpm
  • අධීක්ෂකයකු
  • AMI (තාරක කළමනාකරු අතුරුමුහුණත)
  • Bitrix webhooks (සරල REST API ක්‍රියාත්මක කිරීම)

පෙර සැකසුම

Asterisk සහිත සේවාදායකයක, ඔබ වෙබ් සේවාදායකයක් ස්ථාපනය කළ යුතුය (අපට එය nginx+php-fpm), සුපරීක්ෂක සහ git.

ස්ථාපන විධානය (CentOS):

yum install nginx php-fpm supervisor git

අපි වෙබ් සේවාදායකයට ප්‍රවේශ විය හැකි නාමාවලිය වෙත ගොස්, Git වෙතින් යෙදුම ඇදගෙන ෆෝල්ඩරයට අවශ්‍ය අයිතිවාසිකම් සකසන්න:


cd /var/www
git clone https://github.com/ViStepRU/callme.git
chown nginx. -R callme/

ඊළඟට, අපි nginx වින්‍යාස කරමු, අපගේ වින්‍යාසය පිහිටා ඇත

/etc/nginx/conf.d/pbx.vistep.ru.conf

server {
	server_name www.pbx.vistep.ru pbx.vistep.ru;
	listen *:80;
	rewrite ^  https://pbx.vistep.ru$request_uri? permanent;
}

server {
#        listen *:80;
#	server_name pbx.vistep.ru;


	access_log /var/log/nginx/pbx.vistep.ru.access.log main;
        error_log /var/log/nginx/pbx.vistep.ru.error.log;

    listen 443 ssl http2;
    server_name pbx.vistep.ru;
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pbx.vistep.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.ru/privkey.pem;
    ssl_dhparam /etc/nginx/certs/dhparam.pem;
    ssl_session_timeout 24h;
    ssl_session_cache shared:SSL:2m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers kEECDH+AES128:kEECDH:kEDH:-3DES:kRSA+AES128:kEDH+3DES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2;
    ssl_prefer_server_ciphers on;
    add_header Strict-Transport-Security "max-age=31536000;";
    add_header Content-Security-Policy-Report-Only "default-src https:; script-src https: 'unsafe-eval' 'unsafe-inline'; style-src https: 'unsafe-inline'; img-src https: data:; font-src https: data:; report-uri /csp-report";
	
	root /var/www/callme;
	index  index.php;
        location ~ /. {
                deny all; # запрет для скрытых файлов
        }

        location ~* /(?:uploads|files)/.*.php$ {
                deny all; # запрет для загруженных скриптов
        }

        location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                access_log off;
                log_not_found off;
                expires max; # кеширование статики
        }

	location ~ .php {
		root /var/www/callme;
		index  index.php;
		fastcgi_pass unix:/run/php/php5.6-fpm.sock;
	#	fastcgi_pass 127.0.0.1:9000;
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
		include /etc/nginx/fastcgi_params;
		}
}

වින්‍යාසය විග්‍රහ කිරීම, ආරක්ෂක ගැටළු, සහතිකයක් ලබා ගැනීම සහ ලිපියේ විෂය පථයෙන් පිටත වෙබ් සේවාදායකයක් තෝරා ගැනීම පවා මම තබමි - මේ ගැන බොහෝ දේ ලියා ඇත. යෙදුමට සීමාවන් නොමැත, එය http සහ https දෙකෙහිම ක්‍රියා කරයි.

අපි https භාවිතා කරමු, සහතිකය සංකේතනය කරමු.

ඔබ සියල්ල නිවැරදිව කළේ නම්, සබැඳිය ක්ලික් කිරීමෙන් ඔබට මෙවැනි දෙයක් දැකිය යුතුය

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

Bitrix24 පිහිටුවීම

අපි webhook දෙකක් නිර්මාණය කරමු.

එන webhook.

පරිපාලක ගිණුම යටතේ (ID 1 සමඟ), මාර්ගය අනුගමනය කරන්න: යෙදුම් -> Webhooks -> webhook එක් කරන්න -> එන webhook

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

තිරපිටපත්වල මෙන් එන webhook හි පරාමිතීන් පුරවන්න:

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

සහ සුරකින්න ක්ලික් කරන්න.

සුරැකීමෙන් පසු, Bitrix24 විසින් එන webhook හි URL ලබා දෙනු ඇත, උදාහරණයක් ලෙස:

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

ඔබගේ URL අනුවාදය අවසාන /profile/ නොමැතිව සුරකින්න - එය ලැබෙන ඇමතුම් සමඟ වැඩ කිරීමට යෙදුම තුළ භාවිතා කරනු ඇත.

මට මේක තියෙනවා https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

පිටතට යන webhook.

යෙදුම් -> Webhooks -> webhook එක් කරන්න -> Outgoing webhook

විස්තර නැවතත් තිරපිටපත්වල ඇත:

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

අවසර කේතය සුරකින්න සහ ලබා ගන්න

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

මට මේක තියෙනවා xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. ඔබට එය ඔබ වෙනුවෙන් පිටපත් කිරීමටද අවශ්‍ය වේ; පිටතට යන ඇමතුම් ගැනීමට ඔබට එය අවශ්‍ය වේ.

වැදගත්!

SSL සහතිකයක් Bitrix24 සේවාදායකයේ වින්‍යාස කළ යුතුය (ඔබට letsencrypt භාවිතා කළ හැක), එසේ නොමැතිනම් Bitrix api ක්‍රියා නොකරනු ඇත. ඔබට වලාකුළු අනුවාදයක් තිබේ නම්, කරදර නොවන්න - එය දැනටමත් ssl ඇත.

වැදගත්!

"ප්රොසෙසර් ලිපිනය" ක්ෂේත්රයේ අන්තර්ජාලයෙන් ප්රවේශ විය හැකි ලිපිනයක් අඩංගු විය යුතුය!

අවසාන ස්පර්ශයක් ලෙස, අපි ඇමතුම් ලබා ගැනීම සඳහා යෙදුමක් ලෙස අපගේ CallMeOut ස්ථාපනය කරමු (එබැවින් ඔබ PBX හි අංකය මත ක්ලික් කළ විට, ඇමතුම ආරම්භ කිරීමේ විධානය ඉවතට පියාසර කරනු ඇත).

මෙනුවේ, තෝරන්න: More -> Telephony -> More -> Settings, "Default outgoing Call number" යෙදුම: CallMeOut සහ "Save" ක්ලික් කරන්න

Asterisk සහ Bitrix24 ඒකාබද්ධ කිරීම

තරු ලකුණ පිහිටුවීම

Asterisk සහ Bitrix24 අතර සාර්ථක අන්තර්ක්‍රියා සඳහා, අපි manager.conf වෙත AMI පරිශීලක callme එක් කළ යුතුය:

[callme]
secret = JD3clEB8_f23r-3ry84gJ
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
permit= 10.100.111.249/255.255.255.255
permit = 192.168.254.0/255.255.255.0
read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
write = system,call,agent,log,verbose,user,config,command,reporting,originate

ඊළඟට, dialplan හරහා ක්‍රියාත්මක කිරීමට අවශ්‍ය උපක්‍රම කිහිපයක් තිබේ (අපට මෙය extensions.ael වේ).

මම සම්පූර්ණ ගොනුව ලබා දෙන්නෙමි, පසුව මම පැහැදිලි කිරීමක් දෙන්නෙමි:

globals {
    WAV=/var/www/pbx.vistep.ru/callme/records/wav; //Временный каталог с WAV
    MP3=/var/www/pbx.vistep.ru/callme/records/mp3; //Куда выгружать mp3 файлы
    URLRECORDS=https://pbx.vistep.ru/callme/records/mp3;
    RECORDING=1; // Запись, 1 - включена.
};

macro recording(calling,called) {
        if ("${RECORDING}" = "1"){
              Set(fname=${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${calling}-${called});
	      Set(datedir=${STRFTIME(${EPOCH},,%Y/%m/%d)});
	      System(mkdir -p ${MP3}/${datedir});
	      System(mkdir -p ${WAV}/${datedir});
              Set(monopt=nice -n 19 /usr/bin/lame -b 32  --silent "${WAV}/${datedir}/${fname}.wav"  "${MP3}/${datedir}/${fname}.mp3" && rm -f "${WAV}/${fname}.wav" && chmod o+r "${MP3}/${datedir}/${fname}.mp3");
	      Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3);
              Set(CDR(filename)=${fname}.mp3);
	      Set(CDR(recordingfile)=${fname}.wav);
              Set(CDR(realdst)=${called});
              MixMonitor(${WAV}/${datedir}/${fname}.wav,b,${monopt});

       };
};


context incoming {
888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // выставляем CallerID если узнали его у Битрикс24
        Set(CallStart=${STRFTIME(epoch,,%s)});  
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

h => {
    Set(CDR_PROP(disable)=true); 
    Set(CallStop=${STRFTIME(epoch,,%s)}); 
    Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)}); 
    ExecIF(${ISNULL(${CallMeDISPOSITION})}?Set(CallMeDISPOSITION=${CDR(disposition)}):NoOP(=== CallMeDISPOSITION already was set ===));  
}

}


context default {

_X. => {
        Hangup();
        }
};


context dial_out {

_[1237]XX => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
        Dial(SIP/${EXTEN},,tTr);
        Hangup();
        }

_11XXX => {
	&recording(${CALLERID(number)},${EXTEN});
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Set(__CallIntNum=${CALLERID(num)});
        Dial(SIP/${EXTEN:2}@toOurAster,,t);
        Hangup();
        }

_. => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Dial(SIP/${EXTEN}@toOurAster,,t);
	Hangup();
        }

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

};

අපි මුල සිටම පටන් ගනිමු: නියෝගය ගෝලීය.

විචල්ය URL වාර්තා සංවාද පටිගත කිරීමේ ලිපිගොනු වෙත URL ගබඩා කරයි, ඒ අනුව Bitrix24 ඒවා සම්බන්ධතා කාඩ්පතට ඇද දමයි.

ඊළඟට අපි මැක්රෝ මැක්රෝ ගැන උනන්දු වෙමු පටිගත කිරීමයි.

මෙන්න, සංවාද පටිගත කිරීමට අමතරව, අපි විචල්යය සකසන්නෙමු සම්පූර්ණ නම.

Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3);

එය සම්පූර්ණ URL එක නිශ්චිත ගොනුවකට ගබඩා කරයි (මැක්රෝ සෑම තැනකම හැඳින්වේ).

පිටතට යන ඇමතුම විශ්ලේෂණය කරමු:

_. => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Dial(SIP/${EXTEN}@toOurAster,,t);
	Hangup();
        }

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

අපි කියමු අපි 89991234567 අමතන්න, මුලින්ම අපි මෙතැනට ආවා:

&recording(${CALLERID(number)},${EXTEN});

එම. සංවාද පටිගත කිරීමේ මැක්රෝ කැඳවනු ලබන අතර අවශ්ය විචල්යයන් සකසා ඇත.

තවදුරටත්

        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});

අපි ඇමතුම ආරම්භ කළේ කවුරුන්ද යන්න වාර්තා කර ඇමතුමේ ආරම්භක වේලාව සටහන් කරමු.

සහ එය අවසන් වූ පසු, විශේෂ සන්දර්භයක් තුළ h

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

මෙම දිගුව සඳහා CDR වගුවට ඇතුළුවීම අක්‍රීය කරන්න (එය එහි අවශ්‍ය නොවේ), ඇමතුමේ අවසාන කාලය සකසන්න, කාලසීමාව ගණනය කරන්න, ඇමතුමේ ප්‍රති result ලය නොදන්නේ නම් - සකසන්න (විචල්‍යය CallMeDISPOSITION) සහ, අවසාන පියවර, පද්ධති curl හරහා Bitrix වෙත සියල්ල යවන්න.

තව ටිකක් මැජික් - එන ඇමතුමක්:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // выставляем CallerID если узнали его у Битрикс24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // начинаем отсчет времени звонка
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

මෙහිදී අපි උනන්දු වන්නේ එක් පේළියකට පමණි.

ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp());

ඇය PBX හට ස්ථාපනය කරන ලෙස පවසයි අමතන්නාගේ ID(නම) විචල්‍යයට සමානයි CallMeCallerIDName.

CallMeCallerIDName විචල්‍යය, අනෙක් අතට, CallMe යෙදුම මඟින් සකසා ඇත (Bitrix24 අමතන්නාගේ අංකය සඳහා සම්පූර්ණ නමක් තිබේ නම්, එය සකසන්න අමතන්නාගේ ID(නම), නැත - අපි කිසිවක් නොකරමු).

යෙදුම සැකසීම

යෙදුම් සැකසුම් ගොනුව - /var/www/pbx.vistep.ru/config.php

යෙදුම් පරාමිතීන් විස්තරය:

  • CallMeDEBUG - 1 නම්, යෙදුම මඟින් සකසන ලද සියලුම සිදුවීම් ලොග් ගොනුවට ලියා ඇත, 0 - අපි කිසිවක් ලියන්නේ නැත
  • තාක්ෂණික - SIP/PJSIP/IAX/etc
  • authToken — Bitrix24 අවසර ටෝකනය, පිටතට යන webhook අවසර කේතය
  • bitrixApiUrl - පැතිකඩ නොමැතිව එන webhook හි URL/
  • දිගු කිරීම් - බාහිර සංඛ්යා ලැයිස්තුව
  • සන්දර්භය - ඇමතුමක් ආරම්භ කිරීම සඳහා සන්දර්භය
  • සවන්දෙන්නා_කාලය ඉවරයි - තරු ලකුණෙන් සිදුවීම් සැකසීමේ වේගය
  • තරු ලකුණු - තරු ලකුණට සම්බන්ධ කිරීම සඳහා සැකසුම් සහිත අරාවක්:
  • සත්කාරකය — ip හෝ තරු ලකුණ සේවාදායකයේ සත්කාරක නාමය
  • යෝජනා ක්රමය - සම්බන්ධතා රූප සටහන (tcp://, tls://)
  • වරාය - වරාය
  • පරිශීලක නාමය - පරිශීලක නාමය
  • රහස් - මුරපදය
  • සම්බන්ධ_කාලය අවසන් - සම්බන්ධතා කාලය අවසන් වීම
  • කියවීම_කාලය අවසන් වීම - කල් ඉකුත්වීම කියවීම

උදාහරණ සැකසුම් ගොනුව:

 <?php
return array(

        'CallMeDEBUG' => 1, // дебаг сообщения в логе: 1 - пишем, 0 - не пишем
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //токен авторизации битрикса
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', //url к api битрикса (входящий вебхук)
        'extentions' => array('888999'), // список внешних номеров, через запятую
        'context' => 'dial_out', //исходящий контекст для оригинации звонка
        'asterisk' => array( // настройки для подключения к астериску
                    'host' => '10.100.111.249',
                    'scheme' => 'tcp://',
                    'port' => 5038,
                    'username' => 'callme',
                    'secret' => 'JD3clEB8_f23r-3ry84gJ',
                    'connect_timeout' => 10000,
                    'read_timeout' => 10000
                ),
        'listener_timeout' => 300, //скорость обработки событий от asterisk

);

අධීක්ෂක සැකසුම

ලැබෙන ඇමතුම් නිරීක්ෂණය කරන සහ Bitrix24 (කාඩ්පත පෙන්වන්න, කාඩ්පත සඟවන්න, ආදිය) සමඟ අන්තර් ක්‍රියා කරන Asterisk CallMeIn.php වෙතින් සිදුවීම් හසුරුවීමේ ක්‍රියාවලිය දියත් කිරීමට සුපරීක්ෂක භාවිතා කරයි.

සෑදිය යුතු සැකසුම් ගොනුව:

/etc/supervisord.d/callme.conf

[program:callme]
command=/usr/bin/php CallMeIn.php
directory=/var/www/pbx.vistep.ru
autostart=true
autorestart=true
startretries=5
stderr_logfile=/var/www/pbx.vistep.ru/logs/daemon.log
stdout_logfile=/var/www/pbx.vistep.ru/logs/daemon.log

යෙදුම දියත් කර නැවත ආරම්භ කරන්න:

supervisorctl start callme
supervisorctl restart callme

යෙදුමේ මෙහෙයුම් තත්ත්වය බැලීම:

supervisorctl status callme
callme                           RUNNING   pid 11729, uptime 17 days, 16:58:07

නිගමනය

එය තරමක් සංකීර්ණ විය, නමුත් පළපුරුදු පරිපාලකයෙකුට එය ක්‍රියාත්මක කිරීමට සහ ඔහුගේ පරිශීලකයින් සතුටු කිරීමට හැකි වනු ඇතැයි මට විශ්වාසයි.

පොරොන්දු වූ පරිදි, github වෙත සබැඳිය.

ප්රශ්න, යෝජනා - කරුණාකර ඒවා අදහස් දැක්වීම්වල තබන්න. එසේම, මෙම ඒකාබද්ධතාවයේ වර්ධනය සිදු වූ ආකාරය ගැන ඔබ උනන්දු වන්නේ නම්, ලියන්න, ඊළඟ ලිපියෙන් මම සියල්ල වඩාත් විස්තරාත්මකව හෙළි කිරීමට උත්සාහ කරමි.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න