Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

Me siguri shumë prej jush, si unë, e keni pasur një ide për të bërë diçka unike. Në këtë artikull do të përshkruaj problemet teknike dhe zgjidhjet me të cilat është dashur të përballem gjatë zhvillimit të PBX. Ndoshta kjo do të ndihmojë dikë të vendosë për idenë e tij dhe dikë të ndjekë rrugën e ecur mirë, sepse kam përfituar edhe nga përvoja e pionierëve.

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

Ideja dhe kërkesat kryesore

Dhe gjithçka filloi thjesht me dashurinë për yll (korniza për ndërtimin e aplikacioneve të komunikimit), automatizimi i telefonisë dhe instalimeve freepbx (ndërfaqja në internet për yll). Nëse nevojat e kompanisë ishin pa specifika dhe binin brenda mundësive freepbx - çdo gjë është e mrekullueshme. I gjithë instalimi u krye brenda XNUMX orëve, kompania mori një PBX të konfiguruar, një ndërfaqe miqësore për përdoruesit dhe trajnim të shkurtër plus mbështetje nëse dëshironi.

Por detyrat më interesante ishin jo standarde dhe më pas nuk ishin aq përrallore. yll mund të bëjë shumë, por për të mbajtur ndërfaqen në internet në gjendje pune, ishte e nevojshme të kaloni shumë herë më shumë kohë. Pra, një detaj i vogël mund të zgjasë shumë më tepër sesa instalimi i pjesës tjetër të PBX. Dhe çështja nuk është se kërkon shumë kohë për të shkruar një ndërfaqe në internet, por thelbi është në veçoritë arkitekturore freepbx. Qasjet dhe metodat e arkitekturës freepbx ishte paraqitur në kohën e php4, dhe në atë moment kishte tashmë php5.6 mbi të cilin gjithçka mund të bëhej më e thjeshtë dhe më e përshtatshme.

Pika e fundit ishte dialplanet grafike në formën e një diagrami. Kur u përpoqa të ndërtoj diçka të tillë për freepbx, kuptova se do të më duhej ta rishkruaja ndjeshëm dhe do të ishte më e lehtë të ndërtoja diçka të re.

Kërkesat kryesore ishin:

  • konfigurim i thjeshtë, i arritshëm në mënyrë intuitive edhe për një administrator fillestar. Kështu, kompanitë nuk kërkojnë mirëmbajtje PBX nga ana jonë,
  • modifikim i lehtë në mënyrë që detyrat të zgjidhen në kohën e duhur,
  • lehtësia e integrimit me PBX. U freepbx nuk kishte API për ndryshimin e cilësimeve, d.m.th. Ju nuk mund, për shembull, të krijoni grupe ose meny zanore nga një aplikacion i palës së tretë, vetëm nga vetë API yll,
  • opensource - për programuesit kjo është jashtëzakonisht e rëndësishme për modifikimet për klientin.

Ideja e zhvillimit më të shpejtë ishte që i gjithë funksionaliteti të përbëhet nga module në formën e objekteve. Të gjithë objektet duhej të kishin një klasë prind të përbashkët, që do të thotë se emrat e të gjitha funksioneve kryesore tashmë janë të njohura dhe për këtë arsye tashmë ka zbatime të paracaktuara. Objektet do t'ju lejojnë të zvogëloni në mënyrë dramatike numrin e argumenteve në formën e vargjeve shoqëruese me çelësat e vargjeve, të cilat mund t'i gjeni në freepbx Ishte e mundur duke ekzaminuar të gjithë funksionin dhe funksionet e ndërlidhura. Në rastin e objekteve, plotësimi automatik banal do të tregojë të gjitha vetitë dhe në përgjithësi do të thjeshtojë jetën shumë herë. Plus, trashëgimia dhe ripërcaktimi tashmë zgjidh shumë probleme me modifikime.

Gjëja tjetër që ngadalësoi kohën e ripërpunimit dhe ia vlente të shmangej ishte dyfishimi. Nëse ekziston një modul përgjegjës për thirrjen e një punonjësi, atëherë të gjitha modulet e tjera që duhet t'i dërgojnë një telefonatë një punonjësi duhet ta përdorin atë dhe jo të krijojnë kopjet e tyre. Pra, nëse keni nevojë të ndryshoni diçka, atëherë do të duhet të ndryshoni vetëm në një vend dhe kërkimi për "si funksionon" duhet të kryhet në një vend, dhe jo të kërkohet gjatë gjithë projektit.

Versioni i parë dhe gabimet e para

Prototipi i parë ishte gati brenda një viti. I gjithë PBX, siç ishte planifikuar, ishte modular, dhe modulet jo vetëm që mund të shtonin funksione të reja për përpunimin e thirrjeve, por edhe të ndryshonin vetë ndërfaqen e internetit.

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php
Po, ideja për të ndërtuar një plan dialplan në formën e një skeme të tillë nuk është e imja, por është shumë e përshtatshme dhe unë bëra të njëjtën gjë për yll.

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

Duke shkruar një modul, programuesit tashmë mund të:

  • krijoni funksionalitetin tuaj për përpunimin e thirrjeve, i cili mund të vendoset në diagram, si dhe në menynë e elementeve në të majtë,
  • krijoni faqet tuaja për ndërfaqen e internetit dhe shtoni shabllonet tuaja në faqet ekzistuese (nëse zhvilluesi i faqes e ka parashikuar këtë),
  • shtoni cilësimet tuaja në skedën kryesore të cilësimeve ose krijoni skedën tuaj të cilësimeve,
  • programuesi mund të trashëgojë nga një modul ekzistues, të ndryshojë një pjesë të funksionalitetit dhe ta regjistrojë atë me një emër të ri ose të zëvendësojë modulin origjinal.

Për shembull, kjo është mënyra se si mund të krijoni menunë tuaj zanore:

......
class CPBX_MYIVR extends CPBX_IVR
{
 function __construct()
 {
 parent::__construct();
 $this->_module = "myivr";
 }
}
.....
$myIvrModule = new CPBX_MYIVR();
CPBXEngine::getInstance()->registerModule($myIvrModule,__DIR__); //Зарегистрировать новый модуль
CPBXEngine::getInstance()->registerModuleExtension($myIvrModule,'ivr',__DIR__); //Подменить существующий модуль

Zbatimet e para komplekse sollën krenarinë e parë dhe zhgënjimet e para. U gëzova që funksionoi, që tashmë isha në gjendje të riprodhoja tiparet kryesore freepbx. U gëzova që njerëzve u pëlqeu ideja e skemës. Kishte ende shumë opsione për të thjeshtuar zhvillimin, por edhe në atë kohë disa nga detyrat tashmë po bëheshin më të lehta.

API për ndryshimin e konfigurimit të PBX ishte një zhgënjim - rezultati nuk ishte aspak ai që donim. Unë mora të njëjtin parim si në freepbx, duke klikuar butonin Apliko, i gjithë konfigurimi rikrijohet dhe modulet rifillojnë.

Duket kështu:

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php
*Dialplan është një rregull (algoritëm) me të cilin përpunohet një thirrje.

Por me këtë opsion, është e pamundur të shkruani një API normale për ndryshimin e cilësimeve të PBX. Së pari, operacioni i aplikimit të ndryshimeve në yll shumë i gjatë dhe me burime intensive.
Së dyti, nuk mund të telefononi dy funksione në të njëjtën kohë, sepse të dyja do të krijojnë konfigurimin.
Së treti, ai zbaton të gjitha cilësimet, përfshirë ato të bëra nga administratori.

Në këtë version, si në Askozia, ishte e mundur të gjenerohej konfigurimi i vetëm moduleve të ndryshuara dhe të rindizeshin vetëm modulet e nevojshme, por të gjitha këto janë gjysmë masa. Ishte e nevojshme të ndryshohej qasja.

Versioni i dytë. Hunda e nxjerrë bishtin e mbërthyer

Ideja për të zgjidhur problemin nuk ishte të rikrijohej konfigurimi dhe plani i numrit yll, por ruani informacionin në bazën e të dhënave dhe lexoni drejtpërdrejt nga baza e të dhënave gjatë përpunimit të thirrjes. yll Unë tashmë dija se si të lexoja konfigurimet nga baza e të dhënave, thjesht ndryshoni vlerën në bazën e të dhënave dhe thirrja tjetër do të përpunohet duke marrë parasysh ndryshimet, dhe funksioni ishte i përsosur për leximin e parametrave të planit të numrit REALTIME_HASH.

Në fund, nuk kishte nevojë as të rifillohej yll kur ndryshoni cilësimet dhe të gjitha cilësimet filluan të aplikohen menjëherë në yll.

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

Ndryshimet e vetme në planin e numrit janë shtimi i numrave shtesë dhe lë të kuptohet se. Por këto ishin ndryshime të vogla pikash

exten=>101,1,GoSub(‘sub-callusers’,s,1(1)); - точечное изменение, добавляется/изменяется через ami

; sub-callusers – универсальная функция генерится при установке модуля.
[sub-callusers]
exten =>s,1,Noop()
exten =>s,n,Set(LOCAL(TOUSERID)=${ARG1})
exten =>s,n,ClearHash(TOUSERPARAM)
exten =>s,n,Set(HASH(TOUSERPARAM)=${REALTIME_HASH(rl_users,id,${LOCAL(TOUSERID)})})
exten =>s,n,GotoIf($["${HASH(TOUSERPARAM,id)}"=""]?return)
...

Mund të shtoni ose ndryshoni lehtësisht një rresht në planin e numrit duke përdorur ami (ndërfaqja e kontrollit yll) dhe nuk kërkohet rinisja e të gjithë planit të telefonimit.

Kjo e zgjidhi problemin me API-në e konfigurimit. Madje mund të hyni drejtpërdrejt në bazën e të dhënave dhe të shtoni një grup të ri ose të ndryshoni, për shembull, kohën e telefonimit në fushën "kohë telefonike" për grupin dhe telefonata tjetër do të zgjasë tashmë kohën e specifikuar (Ky nuk është një rekomandim për veprim, pasi disa operacione API kërkojnë ami thirrjet).

Zbatimet e para të vështira sollën sërish krenarinë dhe zhgënjimin e parë. U gëzova që funksionoi. Baza e të dhënave u bë një lidhje kritike, varësia nga disku u rrit, kishte më shumë rreziqe, por gjithçka funksionoi në mënyrë të qëndrueshme dhe pa probleme. Dhe më e rëndësishmja, tani gjithçka që mund të bëhej përmes ndërfaqes në internet mund të bëhej përmes API-së dhe u përdorën të njëjtat metoda. Për më tepër, ndërfaqja në internet hoqi qafe butonin "aplikoni cilësimet në PBX", të cilin administratorët shpesh e harronin.

Zhgënjimi ishte se zhvillimi u bë më i ndërlikuar. Që nga versioni i parë, gjuha PHP ka gjeneruar një plan telefonimi në gjuhë yll dhe duket krejtësisht e palexueshme, plus vetë gjuha yll për të shkruar një plan dial është jashtëzakonisht primitiv.

Si dukej:

$usersInitSection = $dialplan->createExtSection('usersinit-sub','s');
$usersInitSection
 ->add('',new Dialplanext_gotoif('$["${G_USERINIT}"="1"]','exit'))
 ->add('',new Dialplanext_set('G_USERINIT','1'))
 ->add('',new Dialplanext_gosub('1','s','sub-AddOnAnswerSub','usersconnected-sub'))
 ->add('',new Dialplanext_gosub('1','s','sub-AddOnPredoDialSub','usersinitondial-sub'))
 ->add('',new Dialplanext_set('LOCAL(TECH)','${CUT(CHANNEL(name),/,1)}'))
 ->add('',new Dialplanext_gotoif('$["${LOCAL(TECH)}"="SIP"]','sipdev'))
 ->add('',new Dialplanext_gotoif('$["${LOCAL(TECH)}"="PJSIP"]','pjsipdev'))

Në versionin e dytë, dialplani u bë universal, ai përfshinte të gjitha opsionet e mundshme të përpunimit në varësi të parametrave dhe madhësia e tij u rrit ndjeshëm. E gjithë kjo ngadalësoi shumë kohën e zhvillimit dhe vetë mendimi se edhe një herë ishte e nevojshme të ndërhyhej në planin e telefonit më trishtoi.

Versioni i tretë

Ideja për të zgjidhur problemin nuk ishte të gjenerohej yll dialplan nga php dhe përdorim FastAGI dhe shkruani të gjitha rregullat e përpunimit në vetë PHP. FastAGI Kjo i lejon yll, për të përpunuar thirrjen, lidheni me prizën. Merrni komanda nga atje dhe dërgoni rezultatet. Kështu, logjika e planit dial tashmë është jashtë kufijve yll dhe mund të shkruhet në çdo gjuhë, në rastin tim në PHP.

Kishte shumë prova dhe gabime. Problemi kryesor ishte se unë tashmë kisha shumë klasa/skedarë. U deshën rreth 1,5 sekonda për të krijuar objekte, për t'i inicializuar dhe për të regjistruar njëri-tjetrin me njëri-tjetrin, dhe kjo vonesë për thirrje nuk është diçka që mund të shpërfillet.

Inicializimi duhet të kishte ndodhur vetëm një herë dhe për këtë arsye kërkimi për një zgjidhje filloi me shkrimin e një shërbimi në php duke përdorur Fijet. Pas një jave eksperimentimi, ky opsion u la në sirtar për shkak të ndërlikimeve të mënyrës se si funksionon kjo shtesë. Pas një muaji testimi, më duhej gjithashtu të braktisja programimin asinkron në PHP; më duhej diçka e thjeshtë, e njohur për çdo fillestar të PHP-së dhe shumë shtesa për PHP janë sinkrone.

Zgjidhja ishte shërbimi ynë me shumë fije në C, i cili u përpilua me të PHPLIB. Ai ngarkon të gjithë skedarët php ATS, pret që të gjitha modulet të inicializohen, i shton një thirrje mbrapsht njëri-tjetrit dhe kur gjithçka është gati, e ruan atë në memorie. Kur pyesni nga FastAGI krijohet një rrymë, një kopje nga cache e të gjitha klasave dhe të dhënat riprodhohet në të dhe kërkesa i kalohet funksionit php.

Me këtë zgjidhje, koha nga dërgimi i një telefonate në shërbimin tonë në komandën e parë yll u ul nga 1,5s në 0,05s dhe kjo kohë varet pak nga madhësia e projektit.

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

Si rezultat, koha për zhvillimin e planit dial u zvogëlua ndjeshëm, dhe unë mund ta vlerësoj këtë pasi më duhej të rishkruaja të gjithë planin e numrit të të gjitha moduleve në PHP. Së pari, metodat duhet të shkruhen tashmë në php për të marrë një objekt nga baza e të dhënave; ato ishin të nevojshme për t'u shfaqur në ndërfaqen në internet, dhe së dyti, dhe kjo është gjëja kryesore, më në fund është e mundur të punohet me lehtësi me vargje me numra dhe vargje. me bazën e të dhënave plus shumë shtesa PHP.

Për të përpunuar planin e numrit në klasën e modulit, duhet të zbatoni funksionin dialplanDynamicCall dhe argumenti pbxCallKërkesë do të përmbajë një objekt për të bashkëvepruar yll.

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

Për më tepër, u bë i mundur korrigjimi i planit të numrit (php ka xdebug dhe funksionon për shërbimin tonë), mund të lëvizni hap pas hapi duke parë vlerat e variablave.

Të dhënat e thirrjes

Çdo analizë dhe raporte kërkon të dhëna të mbledhura saktë, dhe ky bllok PBX kaloi gjithashtu shumë prova dhe gabime nga versioni i parë në të tretën. Shpesh, të dhënat e thirrjes janë një shenjë. Një thirrje = një regjistrim: kush thirri, kush u përgjigj, sa kohë folën. Në opsionet më interesante, ekziston një shenjë shtesë që tregon se cili punonjës i PBX është thirrur gjatë telefonatës. Por e gjithë kjo mbulon vetëm një pjesë të nevojave.

Kërkesat fillestare ishin:

  • kurseni jo vetëm se kush telefonoi PBX, por edhe kush u përgjigj, sepse ka përgjime dhe kjo duhet të merret parasysh kur analizohen thirrjet,
  • kohë para lidhjes me një punonjës. Në freepbx dhe disa PBX të tjera, thirrja konsiderohet e përgjigjur sapo PBX merr telefonin. Por për menynë zanore ju tashmë duhet të merrni telefonin, kështu që të gjitha telefonatat përgjigjen dhe koha e pritjes për një përgjigje bëhet 0-1 sekondë. Prandaj, u vendos që të kursehet jo vetëm koha para një përgjigjeje, por koha para lidhjes me modulet kryesore (moduli vetë e vendos këtë flamur. Aktualisht është "Punonjës", "Linja e jashtme"),
  • për një plan telefonik më kompleks, kur një thirrje udhëton midis grupeve të ndryshme, ishte e nevojshme që të mund të ekzaminohej secili element veç e veç.

Opsioni më i mirë doli të ishte kur modulet PBX dërgojnë informacione për veten e tyre në thirrje dhe në fund e ruajnë informacionin në formën e një peme.

Duket kështu:

Së pari, informacione të përgjithshme rreth thirrjes (si gjithë të tjerët - asgjë e veçantë).

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

  1. Mora një telefonatë në një linjë të jashtme "Për provën“Në orën 05:55:52 nga numri 89295671458 në numrin 89999999999, në fund është përgjigjur nga një punonjës”Sekretari 2» me numrin 104. Klienti priti 60 sekonda dhe foli 36 sekonda.
  2. punonjës"Sekretari 2"Bën një telefonatë në 112 dhe një punonjës përgjigjet"Menaxheri 1» pas 8 sekondash. Ata flasin për 14 sekonda.
  3. Klienti transferohet te Punonjësi "menaxher 1“ ku vazhdojnë të flasin edhe për 13 sekonda

Por kjo është maja e ajsbergut; për çdo regjistrim mund të merrni një histori të detajuar të thirrjeve përmes PBX.

Historia e një projekti ose si kalova 7 vjet duke krijuar një PBX bazuar në Asterisk dhe Php

Të gjitha informacionet paraqiten si një fole e thirrjeve:

  1. Mora një telefonatë në një linjë të jashtme "Për provën» në 05:55:52 nga numri 89295671458 në numrin 89999999999.
  2. Në 05:55:53 linja e jashtme dërgon një telefonatë në qarkun hyrës "provë»
  3. Kur përpunoni një telefonatë sipas skemës, moduli "thirrja e menaxherit", në të cilën thirrja është 16 sekonda. Ky është një modul i zhvilluar për klientin.
  4. Moduli "thirrja e menaxherit"I dërgon një telefonatë punonjësit përgjegjës për numrin (klientin)"Menaxheri 1” dhe pret 5 sekonda për një përgjigje. Menaxheri nuk u përgjigj.
  5. Moduli "thirrja e menaxherit"i dërgon një telefonatë grupit"menaxherët e CORP" Këta janë menaxherë të tjerë të të njëjtit drejtim (të ulur në të njëjtën dhomë) dhe presin 11 sekonda për një përgjigje.
  6. Grupi "menaxherët e CORP"thirr punonjësit"Menaxheri 1, Menaxheri 2, Menaxheri 3“Njëkohësisht për 11 sekonda. Pa pergjigje.
  7. Thirrja e menaxherit përfundon. Dhe qarku dërgon një telefonatë në modul "Zgjedhja e një rruge nga 1c" Gjithashtu një modul i shkruar për klientin. Këtu telefonata u përpunua për 0 sekonda.
  8. Qarku dërgon një telefonatë në menunë e zërit "Bazë me telefonim shtesë" Klienti priti atje për 31 sekonda, nuk kishte telefonim shtesë.
  9. Skema i dërgon një telefonatë Grupit "Sekretarët“, ku klienti ka pritur 12 sekonda.
  10. Në një grup, 2 punonjës thirren në të njëjtën kohë "Sekretari 1"Dhe"Sekretari 2"dhe pas 12 sekondash punonjësi përgjigjet"Sekretari 2" Përgjigja e thirrjes kopjohet në thirrjet e prindërve. Rezulton se në grup ai u përgjigj "Sekretari 2", kur telefononte qarku u përgjigj"Sekretari 2"dhe iu përgjigj thirrjes në linjën e jashtme me "Sekretari 2'.

Është ruajtja e informacionit për çdo operacion dhe foleja e tyre që do të bëjë të mundur thjesht bërjen e raporteve. Një raport në menynë zanore do t'ju ndihmojë të zbuloni se sa shumë ndihmon ose pengon. Ndërtoni një raport për thirrjet e humbura nga punonjësit, duke marrë parasysh që thirrja është përgjuar dhe për këtë arsye nuk konsiderohet e humbur, dhe duke marrë parasysh se ishte një telefonatë në grup, dhe dikush tjetër është përgjigjur më herët, që do të thotë se thirrja gjithashtu nuk është humbur.

Një ruajtje e tillë informacioni do t'ju lejojë të merrni secilin grup veç e veç dhe të përcaktoni se sa efektivisht funksionon dhe të ndërtoni një grafik të grupeve të përgjigjura dhe të humbura sipas orës. Ju gjithashtu mund të kontrolloni se sa e saktë është lidhja me menaxherin përgjegjës duke analizuar transferimet pas lidhjes me menaxherin.

Ju gjithashtu mund të kryeni studime mjaft atipike, për shembull, sa shpesh numrat që nuk janë në bazën e të dhënave formojnë shtrirjen e saktë ose sa përqindje e thirrjeve dalëse përcillen në një telefon celular.

Rezultati?

Një specialist nuk kërkohet për të mirëmbajtur PBX; administratori më i zakonshëm mund ta bëjë këtë - testuar në praktikë.

Për modifikime nuk nevojiten specialistë me kualifikime serioze, mjafton njohja e PHP, sepse Modulet janë shkruar tashmë për protokollin SIP, dhe për radhën, dhe për thirrjen e një punonjësi dhe të tjerë. Ekziston një klasë mbështjellëse për yll. Për të zhvilluar një modul, një programues mund (dhe në një mënyrë të mirë duhet) të thërrasë module të gatshme. Dhe njohuri yll janë krejtësisht të panevojshme nëse klienti kërkon të shtojë një faqe me ndonjë raport të ri. Por praktika tregon se megjithëse programuesit e palëve të treta mund ta përballojnë atë, ata ndihen të pasigurt pa dokumentacion dhe mbulim normal të komenteve, kështu që ka ende vend për përmirësim.

Modulet mund të:

  • të krijojë aftësi të reja për përpunimin e thirrjeve,
  • shtoni blloqe të reja në ndërfaqen e internetit,
  • trashëgoni nga ndonjë prej moduleve ekzistuese, ripërcaktoni funksionet dhe zëvendësoni atë, ose thjesht të jetë një kopje paksa e modifikuar,
  • shtoni cilësimet tuaja në shabllonin e cilësimeve të moduleve të tjera dhe shumë më tepër.

Cilësimet e PBX përmes API. Siç përshkruhet më sipër, të gjitha cilësimet ruhen në bazën e të dhënave dhe lexohen në momentin e telefonatës, kështu që ju mund të ndryshoni të gjitha cilësimet e PBX përmes API-së. Kur telefononi API, konfigurimi nuk rikrijohet dhe modulet nuk rifillohen, prandaj, nuk ka rëndësi se sa cilësime dhe punonjës keni. Kërkesat API ekzekutohen shpejt dhe nuk bllokojnë njëra-tjetrën.

PBX ruan të gjitha operacionet kryesore me telefonata me kohëzgjatje (në pritje/bisedë), me fole dhe në terma PBX (punonjës, grup, linjë e jashtme, jo kanal, numër). Kjo ju lejon të krijoni raporte të ndryshme për klientë të veçantë dhe pjesa më e madhe e punës është të krijoni një ndërfaqe miqësore për përdoruesit.

Koha do të tregojë se çfarë do të ndodhë më pas. Ka ende shumë nuanca që duhen ribërë, ka ende shumë plane, por ka kaluar një vit nga krijimi i versionit të 3-të dhe tashmë mund të themi se ideja po funksionon. Disavantazhi kryesor i versionit 3 janë burimet e harduerit, por zakonisht kjo është ajo që duhet të paguani për lehtësinë e zhvillimit.

Burimi: www.habr.com

Shto një koment