ആദ്യമായി ഒരു പൈത്തൺ (Python) ട്യൂട്ടോറിയൽ കാണുന്ന മിക്ക ആളുകളും വേരിയബിളുകൾ (variables), ലൂപ്പുകൾ (loops), പ്രായോഗികമായി എന്തെങ്കിലും നിർമ്മിക്കുക എന്നിവയിലേക്ക് നേരിട്ട് കടക്കാൻ ആഗ്രഹിക്കുന്നു. ആ ആവേശം മനസ്സിലാക്കാവുന്നതേയുള്ളൂ. എന്നാൽ പൈത്തൺ യഥാർത്ഥത്തിൽ എന്താണെന്നും അത് അതിന്റെ താഴെയുള്ള മെഷീനുമായി എങ്ങനെ ബന്ധപ്പെട്ടിരിക്കുന്നു എന്നും മനസ്സിലാക്കാൻ നിങ്ങൾ സമയം ചെലവഴിച്ചാൽ, ഭാവിയിൽ നിങ്ങളുടെ കോഡിലെ പിശകുകൾ (debug) വളരെ കുറഞ്ഞ ആശയക്കുഴപ്പത്തോടെ പരിഹരിക്കാൻ നിങ്ങൾക്ക് കഴിയും. പ്രോഗ്രാമിംഗ് ഭാഷകളെല്ലാം ഒരേപോലെയല്ല. അവ വ്യത്യസ്തമായ അബ്സ്ട്രാക്ഷൻ (abstraction) തലങ്ങളിൽ നിലകൊള്ളുന്നു, സൗകര്യത്തിനായി നിയന്ത്രണങ്ങൾ (control) വ്യത്യസ്ത രീതികളിൽ വിട്ടുകൊടുക്കുന്നു, കൂടാതെ വ്യത്യസ്ത പാതകളിലൂടെ പ്രോസസറിലേക്ക് എത്തുന്നു. ആ ഇക്കോസിസ്റ്റത്തിൽ പൈത്തൺ വളരെ പ്രത്യേകമായ ഒരു സ്ഥാനത്താണ് ഇരിക്കുന്നത്. ആ സ്ഥാനം മനസ്സിലാക്കുക എന്നത് പ്രോഗ്രാം ചെയ്യാൻ പഠിക്കുന്നതിനുള്ള ആദ്യത്തെ യഥാർത്ഥ ചുവടുവെപ്പാണ്.
ഭാഷാ ശ്രേണി: പൈത്തൺ എവിടെയാണ് നിലകൊള്ളുന്നത്
ഹാർഡ്വെയറുമായുള്ള സാമീപ്യം അനുസരിച്ച് പ്രോഗ്രാമിംഗ് ഭാഷകളെ പൊതുവെ മൂന്ന് വിഭാഗങ്ങളായി തിരിക്കാം.
ഹൈ-ലെവൽ ഭാഷകൾ (High-level languages) സിലിക്കണിൽ നിന്ന് ഏറ്റവും അകലെയാണ്. പൈത്തൺ, ജാവ (Java), ജാവാസ്ക്രിപ്റ്റ് (JavaScript) എന്നിവയ്ക്കൊപ്പം പൈത്തൺ ഇവിടെയാണ് നിലകൊള്ളുന്നത്. ഈ ഭാഷകൾ മനുഷ്യഭാഷയോട് സാമ്യമുള്ള സിന്റാക്സ് (syntax) ഉപയോഗിക്കുന്നു. മെമ്മറി അഡ്രസ്സുകളും (memory addresses) ബൈനറി നിർദ്ദേശങ്ങളും (binary instructions) കൈകാര്യം ചെയ്യുന്നതിന് പകരം നിങ്ങൾക്ക് user_count = 5 അല്ലെങ്കിൽ print("Hello") എന്ന് എഴുതാം. ഇവ CPU, മെമ്മറി മാനേജ്മെന്റ്, ചിപ്പ്സെറ്റുകൾ തമ്മിലുള്ള വ്യത്യാസങ്ങൾ എന്നിവയെ അബ്സ്ട്രാക്റ്റ് (abstract) ചെയ്യുന്നതിനാൽ, ഒരേ ഹൈ-ലെവൽ കോഡ് തന്നെ മാറ്റങ്ങൾ കുറഞ്ഞ രീതിയിൽ ഒരു Mac, Windows PC അല്ലെങ്കിൽ Linux സെർവറിലും പ്രവർത്തിപ്പിക്കാൻ കഴിയും.
ഈ പോർട്ടബിലിറ്റിക്ക് (portability) ഒരു വില നൽകേണ്ടതുണ്ട്. ഹൈ-ലെവൽ ഭാഷകൾക്ക് ഒരു പരിഭാഷകൻ (translator) ആവശ്യമാണ്. അവയ്ക്ക് പ്രോസസറിൽ നേരിട്ട് പ്രവർത്തിക്കാൻ കഴിയില്ല. നിങ്ങളുടെ വായിക്കാവുന്ന കോഡും മെഷീന്റെ ഇലക്ട്രിക്കൽ സിഗ്നലുകളും തമ്മിലുള്ള അകലം കുറയ്ക്കാൻ നിങ്ങൾക്ക് ഒരു കംപൈലറോ (compiler) അല്ലെങ്കിൽ ഇന്റർപ്രെറ്ററോ (interpreter) ആവശ്യമാണ്. ഇതിന്റെ ഗുണം വികസന വേഗതയാണ് (speed of development). ആദ്യ ദിവസം തന്നെ ഉപയോഗപ്രദമായ പ്രോഗ്രാമുകൾ എഴുതാൻ വേണ്ടി നിങ്ങൾ നേരിട്ടുള്ള ഹാർഡ്വെയർ നിയന്ത്രണം വിട്ടുകൊടുക്കുന്നു.
ലോ-ലെവൽ ഭാഷകൾ (Low-level languages) ഇതിന്റെ നേരെ വിപരീത ദിശയിലാണ്. ഇവ അടിസ്ഥാനപരമായി മെഷീൻ കോഡ് (machine code) ആണ് — പ്രോസസറിന് നേരിട്ട് മനസ്സിലാക്കാൻ കഴിയുന്ന ഒന്ന് (1), പൂജ്യം (0) എന്നിവയുടെ ക്രമങ്ങൾ. മെഷീൻ കോഡ് എഴുതുക എന്നാൽ ചിപ്പിനെപ്പോലെ ചിന്തിക്കുക എന്നാണ് അർത്ഥം. ഏത് മെമ്മറി അഡ്രസ് ആണ് ഉപയോഗിക്കേണ്ടതെന്നും ഏത് CPU രജിസ്റ്ററിൽ (register) ആണ് ഒരു പ്രത്യേക മൂല്യം സൂക്ഷിക്കേണ്ടതെന്നും നിങ്ങൾ തീരുമാനിക്കുന്നു. ഹാർഡ്വെയർ ഇത് ഉടനടി നടപ്പിലാക്കുന്നു, ഇതിന് പരിഭാഷാ സമയമൊന്നും ആവശ്യമില്ല.
ഇതിന്റെ പോരായ്മ കഠിനമായ സങ്കീർണ്ണതയാണ്. ഒരു ലളിതമായ കൂട്ടൽ പോലും പല രജിസ്റ്ററുകൾ മാനുവലായി കൈകാര്യം ചെയ്യുന്നത് ആവശ്യമായേക്കാം. ഒരു തെറ്റായ ബിറ്റ് (bit) പോലും കൃത്യമായ എറർ മെസ്സേജ് ഇല്ലാതെ മുഴുവൻ സിസ്റ്റത്തെയും തകരാറിലാക്കാം. ശുദ്ധമായ മെഷീൻ കോഡ് ഇപ്പോൾ കൈകൊണ്ട് എഴുതാറില്ല, എങ്കിലും ഓരോ പ്രോഗ്രാമും സംസാരിക്കേണ്ട അവസാന ഭാഷയായി അത് നിലനിൽക്കുന്നു.
അസംബ്ലി ഭാഷകൾ (Assembly languages) ഇതിന്റെ ഇടയിലുള്ള ഒരു പരിധിയാണ് കൈയടക്കുന്നത്. അവ ബൈനറി നിർദ്ദേശങ്ങൾക്ക് പകരം 'മ്നെമോണിക്സ്' (mnemonics) എന്ന് വിളിക്കപ്പെടുന്ന മനുഷ്യന് വായിക്കാവുന്ന ചെറിയ ചിഹ്നങ്ങൾ ഉപയോഗിക്കുന്നു. ഒന്ന്, പൂജ്യം എന്നിവയുടെ ഒരു നിരയ്ക്ക് പകരം, ഡാറ്റ നീക്കാൻ MOV എന്നോ കൂട്ടൽ ചെയ്യാൻ ADD എന്നോ നിങ്ങൾക്ക് എഴുതാം. ഈ ചിഹ്നങ്ങൾ ബൈനറിയേക്കാൾ ഓർമ്മിച്ചുവെക്കാൻ എളുപ്പമാണ്, എങ്കിലും അവ ഒരു പ്രത്യേക പ്രോസസർ ആർക്കിടെക്ചറുമായി (processor architecture) ശക്തമായി ബന്ധപ്പെട്ടിരിക്കുന്നു. ഒരു Intel x86 ചിപ്പിനായി എഴുതിയ അസംബ്ലി പ്രോഗ്രാം ഒരു ARM പ്രോസസറിൽ പ്രവർത്തിക്കില്ല.
ഒരു അസംബ്ലർ (assembler) ഈ മ്നെമോണിക്സിനെ മെഷീൻ കോഡിലേക്ക് മാറ്റുന്നു. പൈത്തണിനേക്കാൾ എത്രയോ അധികം നിയന്ത്രണം അസംബ്ലി പ്രോഗ്രാമർമാർക്ക് നൽകുന്നുണ്ടെങ്കിലും, പ്രോസസറിന്റെ പ്രവർത്തനങ്ങളെക്കുറിച്ച് ആഴത്തിലുള്ള അറിവ് അത് ആവശ്യപ്പെടുന്നു. ഇത് ബൈനറിയേക്കാൾ മനുഷ്യചിന്തയോട് അടുത്തതാണെങ്കിലും പ്രോസസറിന്റെ തനതായ ഭാഷ തന്നെയാണ് സംസാരിക്കുന്നത്.
കോഡ് എങ്ങനെ പ്രവർത്തനമായി മാറുന്നു
ഓരോ പ്രോഗ്രാമും ഒടുവിൽ മെഷീൻ നിർദ്ദേശങ്ങളായി മാറണം. സോഴ്സ് കോഡിൽ നിന്ന് പ്രവർത്തിക്കുന്ന ആപ്ലിക്കേഷനിലേക്കുള്ള പാത രണ്ട് തന്ത്രങ്ങളിൽ ഒന്നാണ് പിന്തുടരുന്നത്.
ഒരു കംപൈലർ (compiler) നിങ്ങളുടെ മുഴുവൻ കോഡ് ബേസും ഒറ്റ പാസ്സിലൂടെ പരിഭാഷപ്പെടുത്തുന്നു. നൂറ് വരികളുള്ള ഒരു ഫയൽ നിങ്ങൾ നൽകിയാൽ, അത് പ്രവർത്തിപ്പിക്കാൻ ശ്രമിക്കുന്നതിന് മുമ്പ് നൂറ് വരികളും വായിക്കുകയും വിശകലനം ചെയ്യുകയും ചെയ്യുന്നു. പ്രോഗ്രാമിലുടനീളം സിന്റാക്സ് പിശകുകൾ (syntax errors) ഉണ്ടോ എന്ന് അത് പരിശോധിക്കുന്നു. അമ്പതാം വരിയിൽ ഒരു ടൈപ്പിംഗ് പിശക് ഉണ്ടോ? കംപൈലർ അവിടെ നിൽക്കുന്നു, പ്രശ്നം റിപ്പോർട്ട് ചെയ്യുന്നു, നിങ്ങൾ അത് ശരിയാക്കുന്നത് വരെ പ്രവർത്തിപ്പിക്കാൻ കഴിയുന്ന ഒരു പ്രോഗ്രാം നിർമ്മിക്കാൻ വിസമ്മതിക്കുന്നു.
C, C++ തുടങ്ങിയ ഭാഷകൾ ഈ രീതിയാണ് ഉപയോഗിക്കുന്നത്. ഇതിന്റെ ഫലം സാധാരണയായി വേഗതയ്ക്കായി ഒപ്റ്റിമൈസ് ചെയ്ത ഒരു സ്റ്റാൻഡ്ലോൺ എക്സിക്യൂട്ടബിൾ ഫയൽ (standalone executable file) ആയിരിക്കും. കംപൈലർ കോഡ് മുഴുവൻ മുൻകൂട്ടി പരിശോധിക്കുന്നതിനാൽ, പ്രോഗ്രാം തുടങ്ങുന്നതിന് മുമ്പ് തന്നെ പിശകുകൾ കണ്ടെത്താൻ ഇതിന് കഴിയും. എന്നാൽ ഇതിന് ഒരു പരിധിയുണ്ട്. എഡിറ്റ്-കംപൈൽ-റൺ (edit-compile-run) ചക്രം സമയമെടുക്കുന്ന ഒന്നാണ്. ഒരു വരി മാറ്റിയാൽ പോലും മുഴുവൻ പ്രോജക്റ്റും വീണ്ടും ബിൽഡ് ചെയ്യാൻ നിങ്ങൾ കാത്തിരിക്കേണ്ടി വന്നേക്കാം.
ഒരു ഇന്റർപ്രെറ്റർ (interpreter) തികച്ചും വ്യത്യസ്തമായ ഒരു രീതിയാണ് സ്വീകരിക്കുന്നത്. ഇത് നിങ്ങളുടെ കോഡ് വരി വരിയായി വായിക്കുകയും ഓരോ പ്രസ്താവനയും (statement) പരിഭാഷപ്പെടുത്തി ഉടൻ തന്നെ പ്രവർത്തിപ്പിക്കുകയും ചെയ്യുന്നു. ഫയൽ മുഴുവൻ പരിശോധിച്ചു തീരുന്നത് വരെ ഇത് കാത്തുനിൽക്കുന്നില്ല. പൈത്തൺ REPL-ൽ ഒരു കമാൻഡ് ടൈപ്പ് ചെയ്ത് Enter അമർത്തിയാൽ, ഇന്റർപ്രെറ്റർ ആ ഒറ്റ വരി മാത്രം പ്രോസസ്സ് ചെയ്യുകയും നിർദ്ദേശങ്ങളാക്കി മാറ്റുകയും അവ ഉടൻ തന്നെ പ്രവർത്തിപ്പിക്കുകയും ചെയ്യുന്നു.
ഇത് ഡിബഗ്ഗിംഗിന്റെ രീതിയെ തന്നെ മാറ്റുന്നു. ഒരു ഇന്റർപ്രെറ്റർ ഉപയോഗിക്കുമ്പോൾ, പ്രശ്നമുള്ള വരിയിൽ എത്തുമ്പോൾ മാത്രമാണ് പിശകുകൾ (errors) പുറത്തുവരുന്നത്, അതിനുമുമ്പല്ല. നിങ്ങളുടെ പ്രോഗ്രാം എൺപത് വരികളിലൂടെ കൃത്യമായി പ്രവർത്തിച്ചേക്കാം, എന്നാൽ എൺപത്തിയൊന്നാം വരിയിൽ തകരാറിലാകാം (crash). ആ പെട്ടെന്നുള്ള പ്രതികരണം പഠനത്തിന് ഇന്റർപ്രെറ്ററുകളെ കൂടുതൽ സൗഹൃദപരമാക്കുന്നു. നിങ്ങൾ പരീക്ഷണങ്ങൾ നടത്തുന്നു, ഫലങ്ങൾ കാണുന്നു, തത്സമയം മാറ്റങ്ങൾ വരുത്തുന്നു. Python-ന്റെ സ്റ്റാൻഡേർഡ് ഇംപ്ലിമെന്റേഷനായ CPython യഥാർത്ഥത്തിൽ ഒരു ഹൈബ്രിഡ് മോഡലാണ് ഉപയോഗിക്കുന്നത്: ഇത് നിങ്ങളുടെ സോഴ്സ് കോഡിനെ ബൈറ്റ്കോഡിലേക്ക് കംപൈൽ ചെയ്യുന്നു, തുടർന്ന് ഒരു വെർച്വൽ മെഷീൻ വഴി ആ ബൈറ്റ്കോഡ് പ്രവർത്തിപ്പിക്കുന്നു. ഇതിന് പിന്നിൽ ഒരു ട്രാൻസ്ലേഷൻ ഘട്ടം ഉണ്ടെങ്കിലും, ഇത് ഇന്ററാക്ടീവ് ആയതും വരിവരിയായി പ്രവർത്തിക്കുന്നതുമായ ഒരു അനുഭവം നൽകുന്നു.
എന്തുകൊണ്ടാണ് Python-നെ ഒരു സ്ക്രിപ്റ്റിംഗ് ലാംഗ്വേജ് എന്ന് വിളിക്കുന്നത്
Python പലപ്പോഴും ഒരു സ്ക്രിപ്റ്റിംഗ് ലാംഗ്വേജ് ആയി വിവരിക്കപ്പെടുന്നു. ഈ പേര് അതിന്റെ ഉത്ഭവത്തെയും സാധാരണ ഉപയോഗങ്ങളെയും പ്രതിഫലിപ്പിക്കുന്നു. ഒരു ടാസ്ക് ഓട്ടോമേറ്റ് ചെയ്യാനോ, ടെക്സ്റ്റ് കൈകാര്യം ചെയ്യാനോ, അല്ലെങ്കിൽ വ്യത്യസ്ത പ്രോഗ്രാമുകളെ തമ്മിൽ ബന്ധിപ്പിക്കാനോ വേണ്ടി നിങ്ങൾ ഒരു ചെറിയ ഫയൽ — ഒരു സ്ക്രിപ്റ്റ് — എഴുതുന്നു, അത് നേരിട്ട് പ്രവർത്തിപ്പിക്കുന്നു. ഇന്റർപ്രെറ്റർ തത്സമയം (on the fly) ഈ പരിഭാഷ കൈകാര്യം ചെയ്യുന്നു. നിയന്ത്രിക്കാൻ പ്രത്യേക കംപൈലേഷൻ ഘട്ടങ്ങളോ ട്രാക്ക് ചെയ്യാൻ ബിൽഡ് ആർട്ടീഫാക്റ്റുകളോ ഇതിലില്ല.
സ്ക്രിപ്റ്റിംഗ് ലാംഗ്വേജുകളും ജനറൽ പർപ്പസ് പ്രോഗ്രാമിംഗ് ലാംഗ്വേജുകളും തമ്മിലുള്ള വ്യത്യാസം ഇപ്പോൾ വളരെയധികം കുറഞ്ഞിരിക്കുന്നു. Python ഇന്ന് വലിയ വെബ് ആപ്ലിക്കേഷനുകൾക്കും, ഡാറ്റാ സയൻസ് പൈപ്പ്ലൈനുകൾക്കും, മെഷീൻ ലേണിംഗ് സിസ്റ്റങ്ങൾക്കും കരുത്ത് പകരുന്നു. എന്നിരുന്നാലും, അതിന്റെ അടിസ്ഥാന ആശയം ഇപ്പോഴും നിലനിൽക്കുന്നു. ഒരു ബിൽഡ് സിസ്റ്റം നിയന്ത്രിക്കുന്നതിനേക്കാൾ ഒരു പ്രശ്നം പരിഹരിക്കുന്നതിലാണ് നിങ്ങൾ ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നത്. നിങ്ങൾ ആവശ്യപ്പെടുന്ന നിമിഷം തന്നെ നിങ്ങളുടെ നിർദ്ദേശങ്ങൾ നടപ്പിലാക്കാൻ ഇന്റർപ്രെറ്റർ തയ്യാറായി നിൽക്കുന്നു.
നിലനിൽക്കുന്ന ഒരു അടിത്തറ കെട്ടിപ്പടുക്കാം
ഈ വ്യത്യാസങ്ങൾ വെറും അക്കാദമിക് അറിവുകൾ മാത്രമല്ല. നിങ്ങൾ ആദ്യമായി Python എഴുതി തുടങ്ങുന്ന ആഴ്ചയിൽ നേരിടേണ്ടി വരുന്ന കാര്യങ്ങളെ ഇവ വിശദീകരിക്കുന്നു. എക്സിക്യൂഷൻ സമയത്ത് Python ഒരു SyntaxError കാണിക്കുമ്പോൾ, ഇന്റർപ്രെറ്റർ പരിഭാഷപ്പെടുത്താൻ കഴിയാത്ത ഒരു വരിയിൽ എത്തിയെന്ന് നിങ്ങൾക്ക് ഇപ്പോൾ മനസ്സിലാകും. ചില ജോലികൾക്ക് Python, C-യേക്കാൾ സാവധാനത്തിലാണെന്ന് നിങ്ങൾ വായിക്കുമ്പോൾ, ഇന്റർപ്രെറ്റേഷന്റെയും ഹൈ-ലെവൽ അബ്സ്ട്രാക്ഷന്റെയും (high-level abstraction) ആഘാതം നിങ്ങൾക്ക് മനസ്സിലാകും. നിങ്ങളുടെ സ്ക്രിപ്റ്റുകൾക്കൊപ്പം .pyc ഫയലുകൾ പ്രത്യക്ഷപ്പെടുന്നത് കാണുമ്പോൾ, ഓരോ തവണ റൺ ചെയ്യുമ്പോഴും ടെക്സ്റ്റ് ഫയൽ വീണ്ടും ഇന്റർപ്രെറ്റ് ചെയ്യാതിരിക്കാൻ Python കംപൈൽ ചെയ്ത ബൈറ്റ്കോഡ് കാഷെ (cache) ചെയ്യുന്നുണ്ടെന്ന് നിങ്ങൾ തിരിച്ചറിയുന്നു.
ഭാഷാ ശ്രേണിയിൽ (language hierarchy) Python എവിടെയാണെന്ന് അറിയുന്നത് പിന്നീട് ശരിയായ ടൂൾ തിരഞ്ഞെടുക്കാൻ നിങ്ങളെ സഹായിക്കും. ഓരോ CPU സൈക്കിളും പ്രധാനപ്പെട്ട ഒരു ഡിവൈസ് ഡ്രൈവർ (device driver) എഴുതേണ്ടതുണ്ടോ? അങ്ങനെയെങ്കിൽ നിങ്ങൾ മിക്കവാറും C അല്ലെങ്കിൽ assembly ഉപയോഗിക്കും. ഒരു ഉച്ചകഴിഞ്ഞ് സമയത്തിനുള്ളിൽ ഒരു CSV ഫയൽ പ്രോസസ്സ് ചെയ്യാനോ ഒരു web API നിർമ്മിക്കാനോ ആവശ്യമുണ്ടോ? Python-ന്റെ ഇന്റർപ്രെറ്ററും വായിക്കാവുന്ന സിന്റാക്സും (syntax) കൃത്യമായി അതിനുവേണ്ടിയാണ് നിർമ്മിക്കപ്പെട്ടിരിക്കുന്നത്.
യഥാർത്ഥ പാഠം
Python-ന്റെ കരുത്ത് അതിന്റെ സ്ഥാനത്തുനിന്നാണ് വരുന്നത്. ഇത് ഹാർഡ്വെയറിന് മുകളിൽ നിലകൊള്ളുന്നു, മെഷീൻ സ്പീഡിനേക്കാൾ പ്രോഗ്രാമറുടെ വേഗതയ്ക്ക് പ്രാധാന്യം നൽകുന്ന ഒരു ഇന്റർപ്രെറ്റർ വഴിയാണ് ഇത് പരിഭാഷപ്പെടുത്തപ്പെടുന്നത്. ഈ പശ്ചാത്തലം അറിയാതെ തന്നെ നിങ്ങൾക്ക് സിന്റാക്സ് പഠിക്കാം, എന്നാൽ ഇതിന് പിന്നിലെ പ്രവർത്തനരീതി മനസ്സിലാക്കുന്നത് വരെ നിങ്ങൾക്ക് ബുദ്ധിപരമായി ഡിബഗ് ചെയ്യാനോ അല്ലെങ്കിൽ സഹജമായി ഒപ്റ്റിമൈസ് (optimize) ചെയ്യാനോ കഴിയില്ല. ഈ അടിസ്ഥാന കാര്യങ്ങളിൽ നിന്ന് തുടങ്ങുക. നിങ്ങളുടെ ആദ്യത്തെ യഥാർത്ഥ പ്രോഗ്രാം എഴുതുമ്പോൾ, നിങ്ങൾ വെറും കമാൻഡുകൾ ടൈപ്പ് ചെയ്യുക മാത്രമല്ല ചെയ്യുന്നത്; അവ എങ്ങനെ കൃത്യമായി മെഷീനിലേക്ക് എത്തുന്നു എന്ന് നിങ്ങൾക്കറിയാമായിരിക്കും.
