Asterisk ۽ Bitrix24 جو انضمام

Asterisk ۽ Bitrix24 جو انضمام
نيٽ ورڪ تي IP-PBX Asterisk ۽ CRM Bitrix24 کي ضم ڪرڻ لاءِ مختلف آپشن آهن، پر اسان اڃا به پنهنجو پاڻ لکڻ جو فيصلو ڪيو آهي.

ڪارڪردگي جي لحاظ کان، هر شيء معياري آهي:

  • Bitrix24 ۾ ڪلائنٽ جي فون نمبر سان لنڪ تي ڪلڪ ڪندي، Asterisk صارف جو اندروني نمبر ڳنڍيندو آهي جنهن جي طرفان ڪلائنٽ جي فون نمبر سان ڪلڪ ڪيو ويو هو. Bitrix24 ۾، ڪال جو هڪ رڪارڊ رڪارڊ ڪيو ويو آهي، ۽ ڪال جي آخر ۾، گفتگو جي رڪارڊنگ کي ڇڪايو ويندو آهي.
  • Asterisk ٻاهران هڪ ڪال وصول ڪري ٿو - Bitrix24 انٽرفيس ۾ اسان ملازم کي ڪلائنٽ ڪارڊ ڏيکاريون ٿا جنهن نمبر تي هي ڪال آئي.
    جيڪڏهن اهڙو ڪو به گراهڪ نه آهي، اسان نئين ليڊ ٺاهڻ لاءِ ڪارڊ کولينداسين.
    جيئن ئي ڪال مڪمل ٿئي ٿي، اسان هن کي ڪارڊ تي ظاهر ڪيو ۽ گفتگو جي رڪارڊنگ کي ڇڪيو.

ڪٽ جي هيٺان مان توهان کي ٻڌايان ٿو ته ڪيئن پنهنجي لاءِ هر شي کي ترتيب ڏيو ۽ توهان کي هڪ لنڪ ڏيو github - ها، ها، اهو وٺو ۽ استعمال ڪريو!

عام بيان

اسان اسان جي انضمام کي ڪال مي سڏيو. CallMe ھڪڙو ننڍڙو ويب ايپليڪيشن آھي جيڪو PHP ۾ لکيل آھي.

استعمال ٿيل ٽيڪنالاجيون ۽ خدمتون

  • PHP 5.6
  • PHP AMI لائبريري
  • موسيقار
  • Nginx + php-fpm
  • سپروائزر
  • AMI (Asterisk Manager Interface)
  • Bitrix webhooks (آسان REST API عمل درآمد)

اڳئين سيٽنگ

Asterisk سان سرور تي، توهان کي هڪ ويب سرور نصب ڪرڻ جي ضرورت آهي (اسان لاء اهو آهي nginx + php-fpm)، سپروائيزر ۽ گٽ.

تنصيب حڪم (CentOS):

yum install nginx php-fpm supervisor 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 ترتيب ڏيڻ

اچو ته ٻه webhooks ٺاهي.

ايندڙ ويب هِڪ.

ايڊمنسٽريٽر اڪائونٽ جي تحت (آءِ ڊي 1 سان)، رستي تي عمل ڪريو: ايپليڪيشنون -> ويب هِڪ -> ويب هِڪ شامل ڪريو -> انڪمنگ ويب هِڪ

Asterisk ۽ Bitrix24 جو انضمام

ايندڙ ويب هِڪ جا پيرا ميٽرز ڀريو جيئن اسڪرين شاٽ ۾:

Asterisk ۽ Bitrix24 جو انضمام

Asterisk ۽ Bitrix24 جو انضمام

۽ محفوظ ڪريو تي ڪلڪ ڪريو.

محفوظ ڪرڻ کان پوء، Bitrix24 ايندڙ ويب هک جو URL مهيا ڪندو، مثال طور:

Asterisk ۽ Bitrix24 جو انضمام

پنھنجي URL جو ورجن محفوظ ڪريو فائنل /profile/ کان سواءِ - اھو استعمال ڪيو ويندو ايپليڪيشن ۾ ايندڙ ڪالن سان ڪم ڪرڻ لاءِ.

مون وٽ هي آهي https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

نڪرندڙ ويب هِڪ.

ايپليڪيشنون -> ويب هِڪ -> ويب هِڪ شامل ڪريو -> آئوٽ گوئنگ ويب هِڪ

تفصيل ٻيهر اسڪرين شاٽ تي آهن:

Asterisk ۽ Bitrix24 جو انضمام

Asterisk ۽ Bitrix24 جو انضمام

محفوظ ڪريو ۽ اختياري ڪوڊ حاصل ڪريو

Asterisk ۽ Bitrix24 جو انضمام

مون وٽ هي آهي xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. توھان کي پڻ ان کي پنھنجي لاءِ نقل ڪرڻ جي ضرورت آھي؛ توھان کي ان جي ضرورت آھي ٻاھرين ڪالون ڪرڻ لاءِ.

اھم!

هڪ SSL سرٽيفڪيٽ Bitrix24 سرور تي ترتيب ڏيڻ لازمي آهي (توهان letsencrypt استعمال ڪري سگهو ٿا)، ٻي صورت ۾ Bitrix api ڪم نه ڪندي. جيڪڏهن توهان وٽ ڪلائوڊ ورزن آهي، پريشان نه ڪريو - اهو اڳ ۾ ئي ايس ايس ايل آهي.

اھم!

”پروسيسر ايڊريس“ فيلڊ ۾ لازمي طور تي انٽرنيٽ تان رسائي لائق ائڊريس هجڻ گھرجي!

۽ حتمي رابطي جي طور تي، اچو ته انسٽال ڪريون اسان جي ڪال مي آئوٽ کي ڪال ڪرڻ لاءِ هڪ ايپليڪيشن جي طور تي (جڏهن توهان PBX تي نمبر تي ڪلڪ ڪندا ته ڪال جي شروعات لاءِ ڪمانڊ ڀڄي ويندو).

مينيو ۾، چونڊيو: وڌيڪ -> ٽيليفون -> وڌيڪ -> سيٽنگون، سيٽ ڪريو "ڊفالٽ آئوٽ گوئنگ ڪال نمبر" ايپليڪيشن: ڪال مي آئوٽ ۽ ڪلڪ ڪريو "محفوظ ڪريو"

Asterisk ۽ Bitrix24 جو انضمام

اسٽرڪ قائم ڪرڻ

Asterisk ۽ Bitrix24 جي وچ ۾ ڪامياب رابطي لاء، اسان کي شامل ڪرڻ جي ضرورت آهي AMI صارف ڪالم کي manager.conf:

[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});
}

};

اچو ته شروعات کان شروع ڪريون: هدايت گلوبلز.

متغير URLRECORDS 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});
}

هن ايڪسٽينشن لاءِ سي ڊي آر ٽيبل تي داخلا بند ڪريو (انهي جي ضرورت نه آهي)، ڪال جو آخري وقت مقرر ڪريو، مدت جو حساب ڪريو، جيڪڏهن ڪال جو نتيجو معلوم نه آهي - سيٽ (متغير 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 variable خود، موڙ ۾، CallMe ايپليڪيشن طرفان سيٽ ڪيو ويو آهي (جيڪڏهن Bitrix24 ڪالر جي نمبر لاءِ پورو نالو آهي، ان کي سيٽ ڪريو جيئن ڪالر ID (نالو)، نه - اسان ڪجھ به نه ڪنداسين).

ايپليڪيشن کي ترتيب ڏيڻ

ايپليڪيشن سيٽنگون فائل - /var/www/pbx.vistep.ru/config.php

ايپليڪيشن پيٽرولر جي وضاحت:

  • ڪال ميڊيبگ - جيڪڏهن 1، ته پوءِ ايپليڪيشن پاران پروسيس ٿيل سڀئي واقعا لاگ فائل ۾ لکجي ويندا، 0 - اسان ڪجھ به نه لکندا آهيون
  • هتي - SIP/PJSIP/IAX/etc
  • authToken - Bitrix24 اختيار ڪرڻ وارو ٽوڪن، ٻاهر نڪرڻ وارو ويب هوڪ اختيار ڪرڻ وارو ڪوڊ
  • bitrixApiUrl - ايندڙ ويب هِڪ جو URL، پروفائيل کان سواءِ/
  • واڌايون - خارجي نمبرن جي فهرست
  • راقم - ڪال جي شروعات لاءِ حوالو
  • ٻڌندڙ_وقت ختم - اسٽرڪ کان واقعي جي پروسيسنگ جي رفتار
  • اسٽرڪاس - ستاري سان ڳنڍڻ لاء سيٽنگون سان گڏ هڪ صف:
  • ميزبان - ip يا اسٽرڪ سرور جو ميزبان نالو
  • منصوبو - ڪنيڪشن ڊاگرام (tcp://, tls://)
  • پورٽ - بندرگاهه
  • کاتي جو نالو - استعمال ڪندڙ جو نالو
  • خفيه - پاسورڊ
  • connect_timeout - ڪنيڪشن جو وقت ختم
  • read_timeout - پڙهڻ جو وقت ختم

مثال سيٽنگ فائل:

 <?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

);

نگران سيٽ اپ

Asterisk CallMeIn.php کان ايونٽ هينڊلر جي عمل کي شروع ڪرڻ لاءِ سپروائيزر استعمال ڪيو ويندو آهي، جيڪو ايندڙ ڪالز جي نگراني ڪندو آهي ۽ Bitrix24 سان رابطو ڪندو آهي (ڪارڊ ڏيکاريو، لڪايو ڪارڊ، وغيره).

ٺاھڻ لاء سيٽنگون فائل:

/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

تبصرو شامل ڪريو