Abdullayev Sayidamirxon




Download 256,76 Kb.
bet1/2
Sana26.05.2024
Hajmi256,76 Kb.
#254198
  1   2
Bog'liq
AbdullayevKM2



Abdullayev Sayidamirxon

Xesh algoritmlari dasturiy moduli ustida ishlash



Bizning qidiruv algoritmlarimiz odatda mavhum taqqoslash operatsiyasiga asoslangan. Ushbu ketma-ket, "Belgilar jadvallari va ikkilik qidirish daraxtlari" da tavsiflangan tarqatishni qidirish usuli ajralib turadi, unda i kaliti bo'lgan element to'g'ridan-to'g'ri kirishga imkon beradigan jadvalning i-pozitsiyasida saqlanadi. Distributiv qidirishda taqqoslash operatsiyalari emas, asosiy ko'rsatkichlar massiv ko'rsatkichlari sifatida ishlatiladi; Usulning o'zi kalitlarning jadval indekslari bilan bir xil diapazondagi turli xil sonlar ekanligiga asoslanadi. Ushbu bobda biz hashing usulini ko'rib chiqamiz, bunda kalitlar bunday qulay xususiyatlarga ega bo'lmagan odatdagi qidirish dasturlarida ishlatiladigan tarqatish qidiruvining ilg'or variantidir. Ushbu yondashuvni qo'llashning yakuniy natijasi taqqoslashga asoslangan usullardan mutlaqo farq qiladi - qidirish tugmachalarini elementlardagi kalitlar bilan taqqoslash orqali lug'at ma'lumotlari tuzilmalari bo'ylab harakatlanish o'rniga, kalitlarni jadval manzillariga arifmetik ravishda o'zgartirish orqali jadvaldagi elementlarga kirishga harakat qilamiz.



Xeshni ishlatadigan qidirish algoritmlari ikkita alohida qismdan iborat. Birinchi qadam qidirish kalitini jadvaldagi manzilga o'zgartiradigan hash funktsiyasini hisoblashdir. Ideal holda, turli xil tugmachalarni turli manzillarga solishtirish kerak edi, lekin ko'pincha ikkita yoki undan ko'p turli xil kalitlar jadvalda bir xil manzilni berishi mumkin. Shuning uchun, xesh qidirishning ikkinchi qismi bu kabi tugmachalarni qayta ishlaydigan to'qnashuvni hal qilish jarayoni. Ushbu bobda muhokama qiladigan mojarolarni hal qilish usullaridan biri bog'langan ro'yxatlardan foydalanadi, shuning uchun qidiruv kalitlari sonini oldindan taxmin qilish qiyin bo'lgan holatlarda dinamik vaziyatlarda darhol qo'llanilishini topadi. To'qnashuvlarni hal qilishning qolgan ikkita usuli yuqori natijalarga erishadi ishlash qidirish, chunki narsalar sobit massivda saqlanadi. Ushbu usullarni takomillashtirish usulini ko'rib chiqamiz, bu esa jadval hajmini oldindan aniqlashning iloji bo'lmagan hollarda ulardan foydalanishga imkon beradi.



Hashing - vaqt va xotira o'rtasidagi muvozanatning yaxshi namunasidir. Agar ishlatilgan xotira hajmida hech qanday cheklov bo'lmasa, har qanday qidirishni faqat bitta xotiraga kirish bilan amalga oshirish mumkin, shunchaki kalitni xotira manzili sifatida tarqatish qidiruvidagi kabi ishlatish mumkin. Biroq, bu ideal holat odatda amalga oshirilmaydi, chunki uzun kalitlar juda ko'p xotirani talab qilishi mumkin. Boshqa tomondan, agar cheklovlar bo'lmasa qo'rg'oshin vaqti, ketma-ket qidirish usulidan foydalanib, minimal xotira bilan bajarish mumkin edi. Hashing - bu xotira va vaqtning maqbul miqdoridan foydalanish va ushbu ikkita haddan tashqari talablar o'rtasidagi muvozanatga erishishdir. Xususan, kodni qayta yozish va boshqa algoritmlarni tanlamaslik o'rniga jadvalning hajmini o'zgartirish orqali har qanday muvozanatni saqlashingiz mumkin.



Hashing - bu kompyuter fanining klassik vazifalaridan biri: uning turli xil algoritmlari sinchkovlik bilan o'rganilgan va keng qo'llanilmoqda. Biz shunchaki qat'iy taxminlar bilan emas, jadvalning o'lchamidan qat'i nazar, doimiy bajarilish vaqti bo'lgan belgilar jadvalini topish va kiritish uchun operatsiyalarni qo'llab-quvvatlashiga umid qilamiz.



Kutilayotgan qiymat ramzlar jadvalini har qanday amalga oshirish uchun eng maqbul nazariy samaradorlikdir, ammo hashing hali ham ikkita asosiy sababga ko'ra davo emas. Birinchidan, qo'rg'oshin vaqti haqiqiy dasturlarda uzun tugmalarni ishlatishda ahamiyatli bo'lishi mumkin bo'lgan kalit uzunligiga bog'liq. Ikkinchidan, hashing boshqa belgi yoki saralash kabi belgilar jadvallari bilan boshqa operatsiyalarni samarali bajarilishini ta'minlamaydi. Ushbu bobda biz ushbu va boshqa masalalarni batafsil ko'rib chiqamiz.



Hash funktsiyalari



Avvalo, kalitlarni stol manzillariga o'zgartiradigan xesh funktsiyasini hisoblash muammosini hal qilish kerak. Odatda bu arifmetik hisob-kitobni amalga oshirish qiyin emas, lekin har xil nozik chuqurlarga tushmaslik uchun ehtiyot bo'lish kerak. Agar sizda M elementlari bo'lgan jadval mavjud bo'lsa, sizga klavishlarni butun sonlarga o'zgartiradigan funktsiya kerak. Ideal xesh funktsiyani hisoblash oson va tasodifiy funktsiyaga o'xshab ko'rinishi kerak: har qanday argumentlar uchun natijalar, ma'lum ma'noda, ehtimol teng bo'lishi kerak.



Xesh funktsiyasi kalit turiga bog'liq. To'g'ri aytganda, har bir mumkin bo'lgan kalit turi uchun alohida hash funktsiyasi talab qilinadi. Samaradorlikni oshirish uchun, odatda, arifmetik hisob-kitoblarda ishlatilishi mumkin bo'lgan mashina so'zlaridagi kalitlarning ikkilik tasvirini butun son sifatida ko'rib chiqish g'oyasiga murojaat qilish o'rniga, aniq turdagi konversiyani oldini olish maqsadga muvofiqdir. Hashing yuqori darajadagi tillar oldida paydo bo'ldi - dastlabki kompyuterlarda qiymatni simli kalit yoki butun son sifatida ko'rib chiqish odatiy hol edi. Ba'zi bir yuqori darajadagi tillarda ma'lum bir kompyuterda kalitlarning tasvirlanishiga bog'liq bo'lgan dasturlarni yaratish juda qiyin, chunki bunday dasturlar asosan mashinaga bog'liq va shuning uchun boshqa kompyuterga o'tish qiyin. Odatda, hash funktsiyalari kalitlarni butun sonlarga o'tkazish jarayoniga bog'liq, shuning uchun hash dasturlarida bir vaqtning o'zida ham mashinaning mustaqilligi, ham samaradorligini ta'minlash qiyin bo'lishi mumkin. Odatda, oddiy sonlar yoki suzuvchi nuqta tugmachalari faqat bitta mashinaning ishlashi bilan o'zgartirilishi mumkin, ammo simli tugmalar va boshqa turdagi kompozit kalitlar qimmatroq va samaradorlikka ko'proq e'tibor qaratadi.



Ehtimol, eng oddiy, bu tugmachalar belgilangan diapazondagi raqamlarni o'zgartirish paytida bo'ladi. Masalan, agar kalitlar 0 dan katta bo'lsa va 1 dan kichik bo'lsa, siz ularni M ga ko'paytirib, natijani kichikroq butun songa aylantirib, 0 va M - 1 oralig'ida manzil olishingiz mumkin; bunday misol Fig. 14.1. Agar kalitlar s dan kattaroq va t dan kichik bo'lsa, ularni s sonini ajratish va t-s ga bo'lish orqali o'lchash mumkin, natijada ular 0 dan 1 gacha bo'lgan qiymatlar oralig'iga tushadi va keyin M ga ko'payadi va jadvalda manzilni oladi.

SHA256
import hashlib

def sha256(text):
sha = hashlib.sha256()
sha.update(text.encode('utf-8'))
return sha.hexdigest()

input_text = input("Matnni kiriting: ")
hashed_text = sha256(input_text)
print("Original:", input_text)
print("SHA-256 hash:", hashed_text)

MD5
import hashlib

def md5(text):
return hashlib.md5(text.encode()).hexdigest()

def main():
text = input("Matn kiriting: ")
hashed = md5(text)
print("MD5 hash of '{}': {}".format(text, hashed))

if name == "main":
main()




Shakl 14.1.



0 dan 1 gacha bo'lgan suzuvchi nuqta raqamlarini o'lchamlari 97 ga teng jadval indekslariga aylantirish uchun biz bu raqamlarni 97 ga ko'paytiramiz. Ushbu misolda uchta to'qnashuv yuz berdi: 17, 53 va 76 ga teng bo'lgan indekslar uchun. kalit raqamlar, pastki raqamlar hech qanday rol o'ynamaydi. Hash funktsiyasini ishlab chiqishning maqsadlaridan biri bu nomutanosiblikni bartaraf etishdir, shunda hisoblash paytida har bir bit hisobga olinadi.



Agar kalitlar w-bit sonlari bo'lsa, ularni suzuvchi nuqta raqamlariga aylantirish mumkin va 0 dan 1 gacha bo'lgan suzuvchi nuqtali raqamlarni olish uchun 2 w ga bo'linadi va keyin oldingi paragrafdagi kabi M ga ko'paytiriladi. Agar suzuvchi nuqta bilan ishlash ko'p vaqtni talab qilsa va sonlar oshib ketishiga olib keladigan darajada katta bo'lmasa, butun arifmetik operatsiyalar yordamida bir xil natijani olish mumkin: kalitni M ga ko'paytirish kerak, so'ngra o'ng tomonga o'tish va w raqamlari bilan 2 ga bo'lish kerak. w (yoki, agar ko'paytirish toshib ketishga olib keladigan bo'lsa, siljishni bajaring va keyin ko'paytiring). Bunday usullar xeshlar uchun foydasiz, agar kalitlar diapazon bo'yicha bir tekis taqsimlanmasa, hash qiymati faqat kalitning etakchi raqamlari bilan belgilanadi.



W bitli butun sonlar uchun sodda va samaraliroq usul hashing usullaridan biri hisoblanadi - M o'lchamidagi eng katta stolni tanlash va M ga bo'linishni qolgan qismini hisoblash. h (k) \u003d k mod M har qanday k butun son uchun. Bunday funktsiya modulli xesh funktsiyasi deb ataladi. Hisoblash juda oson (C ++ da k% M) va u M qiymatidan kichik bo'lgan qiymatlar o'rtasida asosiy qiymatlarning teng taqsimlanishiga erishish uchun samaralidir. Kichik misol sek. 14.2.




Shakl 14.2.



O'ng tarafdagi uchta ustun chap tomonda ko'rsatilgan 16 bitli tugmachalarni quyidagi funktsiyalardan foydalanib yutish natijasini ko'rsatadi:



v% 97 (chapda)



v% 100 (markazda) va



(int) (a * v)% 100 (o'ngda),



bu erda a \u003d .618033. Ushbu funktsiyalar uchun jadval o'lchamlari mos ravishda 97, 100 va 100 bo'lib, qiymatlar tasodifiy ko'rinadi (chunki tugmalar tasodifiydir). Ikkinchi funktsiya (v% 100) faqat ikkita tugmachaning o'ng raqamlaridan foydalanadi va shuning uchun tasodifiy bo'lmagan tugmachalar uchun u yomon ishlashi mumkin.



Modulli hashing, shuningdek, suzuvchi nuqta tugmachalariga ham tegishli. Agar kalitlar kichik diapazonga tegishli bo'lsa, siz ularni 0 va 1, 2 w oralig'idagi raqamlarga w-bit sonlarini olish uchun o'lchashingiz mumkin va modulli hash funktsiyasidan foydalanishingiz mumkin. Yana bir variant - modulli hash funktsiyasining operandasi sifatida (agar mavjud bo'lsa) ikkilik kalitlarning vakili sifatida foydalanish.



Modulli xeshlash barcha holatlarda, kalitlarni tashkil etuvchi bitlarga kirish imkoniyati mavjud bo'lganda, ular mashinalar so'zi bilan ifodalangan butun sonlar, mashina so'zida keltirilgan belgilar ketma-ketligi yoki boshqa mumkin bo'lgan variantlardan qat'iy nazar foydalaniladi. Mashina so'ziga kiritilgan tasodifiy belgilar ketma-ketligi tasodifiy butun sonlar bilan bir xil emas, chunki kodlashda hamma bitlardan foydalanilmaydi. Ammo bu ikkala turni (va har qanday boshqa turdagi mashina so'ziga sig'adigan kodlangan) kichkina jadvalda tasodifiy indekslarga o'xshash qilish mumkin.



Modulli xeshlar uchun asosiy raqamni tanlashning asosiy sababi M hash jadvali sifatida sek. 14.3. 7-bitli kodlash bilan belgilar haqidagi ma'lumotlarning ushbu misolida, kalit bazasi bo'lgan raqam sifatida izohlanadi - kalitdagi har bir belgi uchun bitta raqam. Endi so'z 1816567 raqamiga mos keladi, uni ham shunday yozish mumkin



chunki ASCII kodida n, o va w belgilari 1568 \u003d 110, 1578 \u003d 111 va 1678 \u003d 119 raqamlariga mos keladi. Ushbu turdagi kalit uchun M \u003d 64 jadval o'lchamini tanlash muvaffaqiyatsiz tugadi, chunki 64 (yoki 128) ga ko'paytiriladigan x qiymatlarga qo'shish x mod 64 qiymatini o'zgartirmaydi - har qanday kalit uchun, hash funktsiyasining qiymati bu kalitning oxirgi 6 raqamining qiymati. Albatta, yaxshi hash funktsiyasi tugmachaning barcha raqamlarini, ayniqsa belgilar tugmachalarini hisobga olishi kerak. Shunga o'xshash vaziyatlar M darajasining 2-faktorini o'z ichiga olganda yuzaga kelishi mumkin. Buning oldini olishning eng oson yo'li M kabi bosh tanlamoqdir.





Shakl 14.3.



Ushbu jadvalning har bir satrida quyidagilar ko'rsatilgan: 3 harfdan iborat so'z, ASCII kodidagi ushbu so'zning sakkizburchak va o'nlik shakllardagi 21 bitli raqami va 64 va 31-jadvallarning o'lchamlari uchun standart modulli xesh funktsiyalari (ikkita o'ng ustun). 64-jadvalning o'lchami istalmagan natijalarga olib keladi, chunki hash qiymatini olish uchun faqat kalitning o'ng tomonidagi bitlar ishlatiladi va umumiy til so'zlaridagi harflar teng taqsimlanmagan. Masalan, y harfi bilan tugaydigan barcha so'zlarning xesh qiymati 57 ga teng. Aksincha, 31 ning oddiy qiymati jadvalda hajmning yarmidan ko'prog'iga kamroq to'qnashuvlarga olib keladi.



Modulli xeshni amalga oshirish juda oddiy, stolning kattaligi bosh raqam bo'lishi kerak. Ba'zi bir amaliy dasturlar uchun siz ozgina ma'lum bo'lgan tub sonlar bilan qoniqishingiz yoki jadvalning kerakli hajmiga yaqin bo'lgan tub sonlar ro'yxatiga qarashingiz mumkin. Masalan, 2 t - 1 ga teng bo'lgan raqamlar juda muhimdir t \u003d 2, 3, 5, 7, 13, 17, 19 va 31 (va t ning boshqa qiymatlari yo'qligi uchun)





Shakl 14.4.



Ikki n dan kam tub sonlarning jadvali , stolning o'lchami bosh bo'lishi uchun zarur bo'lganda, hash stolni dinamik ravishda tarqatish uchun ishlatilishi mumkin. Berilgan diapazondagi har qanday ijobiy qiymat uchun ushbu jadvaldan undan 2 martaga kam farq qiluvchi ko'payishni aniqlash uchun foydalanish mumkin.



Butun sonli tugmachalarni qayta ishlashning yana bir varianti multiplikativ va modulli usullarni birlashtirishdir: siz kalitni 0 va 1 oralig'idagi doimiyga ko'paytirishingiz kerak, keyin M. bo'linish modulini bajaring. Boshqacha aytganda, siz funktsiyadan foydalanishingiz kerak. Nazariy jihatdan g'ayritabiiy xatti-harakatlarga olib kelishi mumkin bo'lgan qadriyatlar, M va kalitlarni raqamlash tizimining samarali bazasi o'rtasida bog'liqlik mavjud, ammo agar siz a-ning ixtiyoriy qiymatidan foydalansangiz, haqiqiy dasturda har qanday muammo bo'lmaydi. Ko'pincha f \u003d 0.618033 ... (oltin nisbat) ning qiymati a sifatida tanlanadi.



Ushbu mavzudagi boshqa ko'plab o'zgarishlar o'rganildi, xususan, siljitish va niqobni tanlash kabi samarali mashina ko'rsatmalaridan foydalanib bajarilishi mumkin bo'lgan hash funktsiyalari (bog'lanishlar bo'limiga qarang).



Belgilar jadvalidan foydalanadigan ko'plab dasturlarda kalitlar raqam emas va ular qisqa bo'lishi shart emas; tez-tez bu juda uzun bo'lishi mumkin bo'lgan alfanumerik raqamlardir. Averylongkey kabi so'z uchun hash funktsiyasini qanday hisoblash mumkin?



7 bitli ASCII kodida bu so'z 84 bitli raqamga to'g'ri keladi \\ boshlash (tekislang *) 97 \\ cdot 128 ^ (11) va + 118 \\ cdot 128 ^ (10) + 101 \\ cdot 128 ^ (9) + 114 \\ ^ (3) \\\\ + 107 \\ cdot 128 ^ (2) + 101 \\ cdot 128 ^ (1) + 121 \\ cdot 128 ^ (0), \\ end (tekislang *),



ko'pgina kompyuterlar bilan odatiy arifmetik funktsiyalarni bajarish uchun juda katta. Va ko'pincha siz uzoqroq tugmachalarni qayta ishlashingiz kerak.



Uzoq tugmachalar uchun modulli hash funktsiyasini hisoblash uchun ular qismlarga bo'laklarga aylantiriladi. Modul funktsiyasining arifmetik xususiyatlaridan foydalanishingiz va Horner algoritmidan foydalanishingiz mumkin (4.9 "Mavhum ma'lumot turlari" bo'limiga qarang). Ushbu usul tugmachalarga mos keladigan raqamlarni yozishning boshqa usuliga asoslangan. Ko'rib chiqilayotgan misol uchun biz quyidagi ifodani yozamiz: \\ boshlamoq (tekislang *) (((((((((((((((97) cdot 128 ^ (11)) 128) (+) 118) \\ cdot 128 ^ (10) + 101)) 9) + 114) \\ cdot 128 ^ (8) + 121) \\ cdot 128 ^ (7) \\\\ + 108) \\ cdot 128 ^ (6) + 111) \\ cdot 128 ^ (5) + 110) \\ cdot 128 ^ (4) + 103) \\ cdot 128 ^ (3) \\\\ + 107) \\ cdot 128 ^ (2) + 101) \\ cdot 128 ^ (1) + 121. \\ end (tekislang *)



Ya'ni, satrni belgilar kodlashiga mos keladigan o'nlik raqamni chapdan o'ngga qarab ko'rib chiqishda, to'plangan qiymatni 128 ga ko'paytirganda va keyingi belgining kod qiymatini qo'shganda hisoblash mumkin. Uzun simli holatda bu hisoblash usuli oxir-oqibat umuman kompyuterda namoyish etilishi mumkin bo'lganidan kattaroq songa olib keladi. Ammo bu raqam kerak emas, chunki uning M.ga bo'linishidan faqat kichik (kichik) qismi talab qilinadi.Natijani katta to'plangan qiymatni saqlamasdan olish mumkin, chunki hisoblash paytida istalgan vaqtda, siz M ga ko'paygan sonni tashlab yuborishingiz mumkin - har safar ko'paytirsangiz va qo'shsangiz, siz M. bo'linish modulining faqat qolgan qismini saqlashingiz kerak bo'ladi, natijada biz uzoq raqamni hisoblash va keyin bo'linishni amalga oshirish imkoniga ega bo'lgandek bo'lamiz (qarang). mashq 14.10). Ushbu kuzatish uzun simlar uchun modulli xesh funktsiyalarini hisoblash uchun to'g'ridan-to'g'ri arifmetik usulga olib keladi - 14.1 dasturiga qarang. Ushbu dasturda yana bitta, oxirgi hiyla qo'llaniladi: baza 128 o'rniga, u 127 raqamini ishlatadi. Ushbu o'zgarish sababi keyingi paragrafda muhokama qilinadi.



Horner (Horner) usuli yordamida modulli xeshlash bilan bir xil narxda xesh funktsiyalarini hisoblashning ko'p usullari mavjud (har bir belgi uchun bitta yoki ikkita arifmetik amallar). Tasodifiy kalitlar uchun ushbu usullar deyarli bir-biridan farq qilmaydi, ammo haqiqiy kalitlar kamdan-kam hollarda tasodifiydir. Kichkina narxga haqiqiy kalitlarni tasodifiy ko'rish qobiliyati tasodifiy xeshlash algoritmlarini ko'rib chiqishga olib keladi, chunki biz kalitlarning taqsimlanishidan qat'i nazar, tasodifiy jadval indekslarini yaratadigan hash funktsiyalariga muhtojmiz. Tasodifiylashtirishni tashkil qilish qiyin emas, chunki modulli hashing ta'rifiga so'zma-so'z rioya qilish shart emas - faqat M dan kichik bo'lmagan butun sonni hisoblashda kalitning barcha raqamlari ishlatilishi kerak.



M \u003d 96 va a \u003d 128 (yuqorida),



M \u003d 97 va a \u003d 128 (markazda) va



M \u003d 96 va a \u003d 127 (pastki)



Birinchi holda notekis taqsimlash bu harflarning notekis ishlatilishi va jadvalning kattaligi ham, omil ham 32 ga ko'payganligi sababli notekislikni saqlashning natijasidir. Boshqa ikkita misol tasodifiy ko'rinadi, chunki stol kattaligi va omil - bu nusxa raqamlari.



14.1-dastur buni amalga oshirishning bitta usulini ko'rsatadi: 2-quvvat o'rniga oddiy bazadan va ASCII-ning mag'lubiyatiga mos keladigan butun sondan foydalanish. Shaklda 14.5 rasm. 14.5-rasmda ushbu o'zgarish odatiy simli tugmalar uchun taqsimlashni qanday yaxshilaganligi ko'rsatilgan. Nazariy jihatdan, 14.1 dasturi tomonidan yaratilgan xash qiymatlari jadval jadvallari uchun 127 ga teng bo'lgan yomon natijalar berishi mumkin (garchi amalda bu deyarli ko'rinmas bo'lishi mumkin); Tasodifiy algoritmni yaratish uchun multiplikatorning qiymatini tasodifiy tanlash mumkin. Keyinchalik samaraliroq usul - bu hisoblashda koeffitsientlarning tasodifiy qiymatlari va kalitning har bir raqami uchun turli xil tasodifiy qiymatlardan foydalanish. Ushbu yondashuv universal hashing deb nomlangan tasodifiy algoritmni taqdim etadi.



Nazariy jihatdan ideal universal hash funktsiyasi - bu M o'lchamidagi jadvalda ikkita turli xil kalitlarning to'qnashuvi ehtimoli to'liq 1 / M bo'lgan funktsiya. 14.1 dasturida a koeffitsienti sifatida foydalanish qat'iy belgilangan qiymat emas, balki tasodifiy turli xil qiymatlar ketma-ketligi modulli xeshni universal xesh funktsiyasiga o'zgartirishi isbotlanishi mumkin. Biroq, kalitdagi har bir belgi uchun yangi tasodifiy raqamni yaratish qiymati odatda qabul qilinishi mumkin emas. Amalda, 14.1 dasturida ko'rsatilgan murosaga har bir kalit belgisi uchun turli xil tasodifiy raqamlar qatorini saqlash bilan emas, balki oddiy soxta tasodifiy tartib yaratish orqali koeffitsientlarni o'zgartirish orqali erishish mumkin.



Xulosa qilish uchun: mavhum belgilar jadvalini amalga oshirish uchun xeshdan foydalanish uchun avval siz M-jadval jadvalidan kichikroq manfiy bo'lmagan butun sonlarga kalitlarni joylashtiradigan xesh-operatsiyani kiritish uchun mavhum tipli interfeysni kengaytirish kerak.



Ushbu maqolaning bir qismi sifatida sizga aytaman
Download 256,76 Kb.
  1   2




Download 256,76 Kb.