aofsorular.com
BİL107U

Ünite 2: .net Core Teknolojisi ve C# Programlama Dili Giriş

PROGRAMLAMA I
Giriş Program yazmak için tek sermaye insanın hayal gücüdür. Bu sektörde yapılmamışı yapmak kadar yapılmışın daha kullanışlısını yapmak da oldukça önemlidir. Başka bir meslek üzerinde uzmanlaşmış olsak bile, kodlamayı öğrenmek; analitik düşünme ve problem çözme gibi farklı yeteneklerimizi geliştirmemizi sağlayacaktır. Program Nedir Bilgisayarı çalıştırmak için tuşa bastığımızda, arka planda çalışan tüm unsurlar program olarak kabul edilir. Program, çeşitli görevler için tasarlanmış elektronik aygıtlara ne yapması gerektiğini belirten, birbirleri ile aralarındaki iletişimi sağlayan, var olan bir problemi çözmek amacıyla hazırlanmış anlamlı kod bütününe de program diyebiliriz. Programlar; klavye, fare gibi girdilerden gelen verileri ve komutları işleyerek, elde edilen sonuçları ilgili donanım birimlerine aktararak çıktıları elde ederler. Sistem Yazılımları (İşletim Sistemleri) İşletim sistemleri tüm donanım ve yazılımların arasındaki iletişimi belirli kurallar çerçevesinde düzenleyen yazılımlardır. Bunun yanında tüm yazılımların kullandıkları kaynakların planlama ve kontrolünü yaparlar. Hazırlanan yazılımlarla da kullanıcıların donanımlara ve bilgisayar kaynaklarına erişimine izin verilmektedir. Sürücü yazılımlarını da işletim sistemi ile donanım arasındaki iletişimi sağladığı için bu gruba dâhil edebiliriz. İşletim sistemi yazılımlarına Linux, Mac-Os, Windows 10, 8, 7 …, Android (Mobil), IOS (Mobil) örnektir. Uygulama Yazılımları Kullanıcıların genel ihtiyaç ve isteklerine göre hazırlanmış yazılımlardır. Tüm yazılımlar gibi bu yazılımlar da işletim sistemi üzerinde çalışmaktadır. Kendi içlerinde birçok kategoriye ayrılmaktadır. Bunların en bilinenleri: Ticari Yazılımlar: Genellikle firmalar için hazırlanmış, sektöre özel dizayn edilmiş yazılımlardır. Eğlence Yazılımları: Oyunlar, işletim sisteminde kullanılan kişiselleştirilebilir eklentiler, çeşitli video/resim/müzik düzenleme yazılımları gibi Genel Amaçlı Yazılımlar: Bilgisayarların daha performanslı çalışmasını sağlayan uygulamalardır. Programlama Dilleri İşletim sistemleri de dâhil olmak üzere, tüm uygulamalar, bir programlama dilinin ürünüdür. Programlama dillerinin kullandığı arayüzler de yine bir programlama dili ile yazılmıştır. Örneğin C# kodlarının yazıldığı geliştirme ortamı olan MS Visual Studio da bir programlama dili kullanılarak geliştirilmiştir. C#, Java, C, C++, Python gibi programlama dillerini bulunmaktadır. Yazılımlar kullanım haklarına göre de gruplara ayrılmaktadır: Lisanslı Yazılımlar, Ücretsiz Yazılımlar, Sınırlı/Geçici Kullanım Yazılımlar, Beta Yazılımlar, Açık
Kaynak Kodlu Yazılımlar, Kapalı Kaynak Kodlu Yazılımlar. Programlama Dilleri Bilgisayar ile insanlar arasında, ortak olarak anlaşılabilecek şekilde iletişim kurmayı sağlayan, makinenin düzgün ve verimli bir şekilde çalışmasını sağlayan, belli standartları, kuralları olan ve komutlardan oluşan yazılıma programlama dili denilmektedir. Her dilin kendine özgü yazım kuralları vardır. Bilgisayara yaptırılmak istenen işlemler, iş akışına uygun sırada komutlar hâlinde verilmesiyle de yazılımlar oluşturulmuş olur. Bilgisayar da bu sıralanmış komutları düzgün bir şekilde çalıştırarak yapılması istenilen işi gerçekleştirir. Bilgisayara neyi nasıl yapacağı, programlama dili ile anlatılarak yol gösterilmektedir. Bu programlama dillerinin ortak özellikleri olduğu gibi, kendilerine özgü özellikleri de bulunmaktadır. Programlama dili kullanılarak hazırlanan yazılım, belirlenen algoritmaya göre düzenlenmelidir. İlk bilgisayar programının Ada Lovelace tarafından, Charles Babbage’ın tasarladığı “Analytical Engine” için Bernoulli sayılarının hesaplanması amacıyla yazdığı makalesinde olduğu kabul edilmektedir. İlk gerçek anlamdaki bilgisayar programlama dillerinden ADA dilinin adı, Ada Lovelace’in anısına verilmiştir. Programlama dillerini de kendi içinde kategorilere ayırabiliriz. Kategorilere ayrılırken dilin insan algılamasına olan yakınlığına göre bir seviye verilmektedir. Yüksek seviyeli diller insan algılamasına çok daha yakın olurken, alçak seviyeli diller ise bilgisayarın çalışma mantığına daha yakın diller olarak adlandırılabilir. Programlama dilinin seviyesi yükseldikçe programcının işinin kolaylaşmasıyla beraber verimlilik ve esneklikte azalmaktadır. Alçak seviyeli diller ise donanıma bağlı olarak çalışmakla birlikte, makine hâkimiyeti oldukça yüksek dillerdir. Makine ve Assembly dili bu seviyede kullanılır. Assembly dilinde, semboller ile hafıza, işlem ve değişken operasyonları gerçekleştirilmektedir. Kodlaması çok yavaş olmakla birlikte, hata yapmaya çok elverişlidir. Uygulama alanına göre dillerin sınıflandırılmasına ise şu şekilde örnekler verebiliriz:
• Mühendislik ve Bilimsel Alanlarda Programlama (Fortran, C, Pascal, Python)
• Sistem Programlama (C, Assembler)
• Veritabanı Programlama (Dbase, Clipper, FileMaker, Microsoft SQL Server, MySQL, Postgresql)
• Yapay Zeka Programlama (Prolog, LISP, Python)
• Web Programlama (ASP .Net, PHP, JSP)
• Masaüstü Programlama (C#, Java)
• Mobil Programlama (Android, IOS) Derleyici Nedir? Yüksek seviyeli dillerde yazılan programların çalışabilmesi için, bilgisayarın da anlayabileceği makine diline
çevrilmesi gerekmektedir. Her yüksek seviyeli dilin bir derleyicisi bulunmaktadır. Derleyicinin görevi, yüksek seviyeli programlama dili çıktısını makine diline çevirmektir. Çevrim işleminden önce, hazırlanan kodda hata olup olmadığı kontrol edilir. Bulunan hatalar bildirilir, yoksa 0-1’lerden oluşan makine kodu oluşturulur. Hedef kod oluşturulurken derleyici çeşitli iyileştirme/ optimizasyon aşamalarını da uygulamaktadır. Kaynak koda müdahale edilebilirken derleyicinin oluşturduğu hedef kodun içeriğine müdahale imkânı bulunmamaktadır. Derleyiciler olmasaydı, tüm yazılımların makine dilinde hazırlanması gerekecekti. Yorumlayıcı Nedir? Derleyiciler, kaynak kodda hata varsa çalıştırılmadan uyarı verir ve kodu çalıştırmaya izin vermez, hatasız şekilde düzenlenen kodu makine diline çevirdikten sonra çalıştırır. Yorumlayıcılar ise kodu satır satır veya bloklar hâlinde çalıştırırken sırası gelmeyen kod blokları hiç çalıştırılmaz. Programlama Ortamı Programlama ortamı, programların yazılabilmesi için kurulan, birçok bileşenden oluşan bir yapıdır. Bilgisayarın donanımını kontrol ederek yazılım tarafından gönderilen istekleri yerine getirmek için bir araya gelmiş tüm elemanlardır. Bu elemanları inceleyecek olursak;
• Editör: Yazılımcı tarafından hazırlanan kodun oluşturulduğu ve düzenlemeye izin veren bir ortamdır. Programlama dilinin tüm özelliklerinin kullanabileceği araçlara sahiptir. Otomatik kod tamamlama, kullanılmayan değişkenler için verilen uyarılar, hatalı yazılan kod parçalarını kodu yazarken uyarma gibi işlevlere sahiptir.
• Derleyici (Compiler): Editörde hazırlanan kaynak kodu, bilgisayarın makine seviyesinde anlayabileceği makine diline çevirmek için kullanılan bir aracı programdır.
• Kütüphane (Library): Kod içerisinde kullanılacak, daha önce hazırlanmış veri türleri, hazır metotlar ve sınıfları içeren dosyalardır.
• Hata Ayıklayıcı (Debugger): Hazırlanan ve doğru bir şekilde derlenmiş olan kodu adım adım çalıştırarak değişkenlere atanan değerleri görmeye izin veren bir bileşendir. Yazılımcının hatalarını daha kolay ve hızlı bir şekilde bulmasına yardımcı olur. Programlama Dillerinin Elemanları
• Söz dizimi (Syntax): Programlama dilindeki ögelerin (değişken, işlem, sembol, operatör vs.) doğru ve anlamlı bir dizilime sahip olması denilebilir.
• Anlam Bilim (Semantics): Program dilindeki ifadelerin, anlatımların ve program birimlerinin anlamıdır.
• Veri (Data): Bir uygulamada farklı veri türleri ile işlem yapılması gerekebilmektedir.
• Atama Deyimi (Assignment Statement): a = 26; b = 20 gibi satırlar atama deyimine örnek olarak verilebilir.
• Tür Kontrolü (Type Checking): Çalışma esnasında (run time) veya derleme sırasında (compile time) tür kontrolü işlemleri yapılmaktadır. Bu kontroller her işlem öncesinde hataların ve yanlış atamaların önlenmesi amacıyla yapılmaktadır.
• Kontrol Deyimleri: Program kodu içerisinde, kontrol edilecek durumun doğru veya yanlış oluşuna göre yapılacak işlemler karşımıza çıkabilir. Bu durumda devreye kontrol deyimleri girer. Bu kontrol deyimlerine if-else, switch case, while deyimleri örnek olarak gösterilebilir.
• Alt Programlar: Bir programın kodu içerisinde bazı kısımlar birden fazla kullanılabilir. Bu durumda her seferinde aynı kod bloğunun tekrar yazılmasındansa, kodun içerisinden ayrılarak küçük bir alt program oluşturulabilir.
• Modüller: Programlamada kullanılan yöntemlerden biri de aynı görev için özelleşmiş ya da birbiriyle ilişkili fonksiyonlar bir araya toplanarak farklı dosyalarda tutulur. Bu gruplanmış fonksiyonlara modül denir. Programlama Dili Değerlendirme Ölçütleri
• Verimlilik (efficiency): Bir programın genel olarak hızlı, az bellek kullanarak çalışmasına denir.
• Veri türleri ve yapıları (data types and structures): Bünyesinde farklı veri türlerini (tam sayı, gerçek sayı, boolean ve karakter işlemleri gibi) ve veri yapılarını (dizi, ağaç, liste, yapılar gibi) destekleme kabiliyetidir.
• Alt programlama yeteneği (Modularity): Alt programları, büyük bir problemi parçalara ayırarak oluşturulan daha küçük parçaların çözümlenmesi ve bu parçaların aralarında kurulan ilişkilerin yönetimi şeklinde ifade edebiliriz.
• Yapısallık (structural programming support): Kod yazımında bloklar hâlinde yazım öne çıkmaktadır. Alt programlar yoğun şekilde kullanılmaktadır. Kullanılan alt programlar sayesinde kodun okunurluğu ve yönetimi daha kolay olur.
• Esneklik (flexibility): Programlama dilinin makinenin tüm donanım birimlerine erişiminde geniş yetkiler vermesidir diyebiliriz. Yani programcının kısıtlanmaması durumudur.
• Öğrenme ve öğretme kolaylığı (pedagogy): Programlama dillerinin seviyesi yükseldikçe öğrenme ve kod yazması kolaylaşmakta, seviyesi düştükçe de öğrenme ve kod yazımı zorlaşmaktadır.
• Genellik (generality): Bir programlama dilinin sadece belli bir çeşit işlem için değil, çeşitli
uygulamaların geliştirilebilmesine imkân verecek şekilde dizayn edilmesidir.
• Giriş / Çıkış (input / output, IO facility) kolaylığı: Dosya erişimi ve veri tabanı işlemlerinin kolaylıkla yapılabilme yeteneğidir.
• Okunabilirlik (readability): Sorumluluğun büyük ölçüde programı yazan kişide olduğu bir durumdur. Kodun, başkaları tarafından da kolay ve anlaşılabilir bir şekilde yazılmasıdır. Tabii kullanılan dilin de bu konuda okunabilirliği destekleyen yapıları olması gerekmektedir.
• Taşınabilirlik (portability): Taşınabilirlik, kaynak kodun başka sistemlerde de sorunsuz bir şekilde derlenerek doğru şekilde çalıştırılabilmesi demektedir.
• Nesne Yönelimlilik (object orientation): Teknolojildeki gelişmeye bağlı olarak kodların milyon satır düzeylerine ulaştığı görülmektedir. Büyüyen kodların kontrolü de zorlaşmakta olduğundan kullanılan dillerin yapısı değişmiş, nesne yapısı üzerine kurulu diller geliştirilmiştir. Eski dillerin de nesne yönelimli yeni versiyonları piyasaya çıkmıştır. Yapısal Programlama ve Nesne Yönelimli Programlama Yapısal Programlama ve Nesne Yönelimli Programlama iki programlama paradigması olarak karşımıza çıkmaktadır. Bu paradigmalar, programların unsurlarını temsil etmek için kullanılan değişken, nesne, fonksiyon gibi unsurlar ile problem çözümünde kullanılan veri akışı, atama, değerlendirme gibi adımların tanımlanma şekillerine göre farklılıklar göstermektedir. Yapısal Programlama Nedir? Yapısal programlama, 1900’lü yılların ortalarında ortaya çıkmış bir kod yapılandırmasıdır. Bu yapılandırma, hiyerarşik bir şekilde düzenlenmiş, aralarında mantıksal uyum bulunan basit akış yapılarından oluşmaktadır. Buradaki temel amaç, problemi basit alt parçalara bölerek her bir parçanın çözümünün birleştirilmesidir. Böylece daha akıcı, anlaşılır bir kod bütünü oluşturulurken kodlama ve test aşamalarında da kolaylık ve hız kazanılmasını sağlamaktadır. Bu programlama tekniğinde, kod içerisinde aynı alt program bloğu defalarca çağrılabilir. Böylece gereksiz kod tekrarlarının önüne geçilmiş olacaktır. Yapısal programlamanın ortaya çıkmasında temelde iki sebep olduğu söylenebilir. Bunlardan ilki, GOTO komutunun karmaşıklığıdır. Diğer bir sebep de tasarımda kullanılan yöntemlerin uyarlanma zorluğu olarak karşımıza çıkmaktadır. Yapısal programlama ortaya çıkmadan önce, genel kullanıma hitap eden, resmî bir analiz ve tasarım sistemi bulunmuyordu. Mevcut akış şemaları, yapılandırılmış programlama düşüncesinin mantığına bir yenilik getirdiği için tasarım ve analiz aşamalarında da yol gösterici olmuştur. Şu şartları destekleyen diller için yapısal programlama mantığına sahip oldukları söylenebilir:
• Fonksiyon veya prosedür tarzı bir yapı ile bir alt programdan diğerine geçiş
• Mantıksal bir kontrol ile (if) iki alt programdan birisini çalıştırmak
• Bir döngü sayesinde belirlenen şart sağlanana kadar bir alt programın çalıştırılması Bunun yanında, gelişen şartlara göre diğer farklı yaklaşımları da destekleyen diller bulunmaktadır. Yapısal programlama mantığına göre bir tasarım yaparak akış diyagramı hazırlamak istersek aşağıdaki adımları takip etmemiz gerekmektedir.
• Adımların basit bloklara bölünmesi
• Tüm blokların tek bir çıkışı olacak şekilde tekrar tasarlanması ya da bölünmesi
• Çıkış noktaları vasıtasıyla blokların birbirine bağlanması
• Tekrarlı bloklar için döngüler ve koşulların tanımlanması
• Koşullu dallanmalar (if) için şartların tanımlanması
• Bağlantı eksikliklerinin tamamlanması Nesne Yönelimli Programlama (NYP) Nedir? Nesne Yönelimli Programlama (Object Oriented Programming) 1960’lı yılların sonlarına doğru ortaya çıkan bir yazılım geliştirme yaklaşımıdır. NYP, mantıksal işlemler yerine, nesneler ve bu nesneler üzerinde gerçekleştirilen işlemlere odaklanmış bir yapı olarak dizayn edildiği için, karşılaşılan bu sorunlara çözüm getirmiştir. Temel kural olarak her işlev nesneler üzerinden gerçekleşmektedir. Bu yaklaşımda hazırlanan programlar, nesnelerin birbirleri ile iletişime geçmeleri sağlanarak tasarlanmaktadır. NYP yaklaşımlarını destekleyen dillerin tamamına yakını, yapısal programlamayı da bünyelerinde barındırırlar. Önceki yaklaşımların yetersizliklerini şu şekilde listeleyebiliriz:
• Uygulamalar parçalanamaz bir bütün şeklinde olduğundan uygulamayı geliştiren herkesin tüm koda hâkim olması gerekmesi
• Yeni programcıların sisteme entegrasyonu sırasında, tüm kodun fonksiyonel olarak öğrenilmesi için uzun bir süreç gerekmesi
• Yapılan değişikliklerin tüm sistemi etkileyen durumlara neden olabilmesi
• Uygulama maliyetlerinin artması
• Projelerin gittikçe büyümesi, geliştirme sürelerinin uzaması ve zorlaşması Nesne yönelimli programlamayı ilk ortaya atan Alan Kay tarafından önerilen metodolojiyi şu şekilde listeleyebiliriz:
• Uygulamalar, nesneler ve birbirleri ile olan ilişkileri çerçevesinde belirli bir işi yapmak için geliştirilebilmelidir.
• Her nesne bir sınıfa ait olmalıdır ve sınıflar nesnelerin ortak özelliklerini ifade etmelidir.
• Nesneler birbirleri ile iletişime geçebilmelidir.
Temel prensipleri ise şu şekilde sıralayabiliriz:
• Her şey bir nesnedir.
• Nesneler kendi aralarında mesaj iletir ya da istek oluşturur.
• Her nesne kendi bilgilerini tutabilmelidir, bir hafızası olmalıdır.
• Her nesne bir sınıfın örneğidir. Sınıf, benzer nesneleri gruplayan bir şemadır.
• Sınıf içinde nesnelerin özellikleri belirtilir.
• Sınıflar, tek kökü olan bir ağaç yapısı altında dizayn edilir. Buna miras hiyerarşisi denmektedir. Bu yaklaşımda, tüm NYP’ler Kapsülleme (Encapsulation), Miras Alma (Inheritance), Çok Biçimlilik (Polymorphism), Soyutlama (Abstraction) özellikleri gerçekleştirmelidir. Kapsülleme (Encapsulation) Kullanıcı tarafından değişkenlerin, metot ve sınıfların ne kadarının görüntülenerek değiştirilebileceğinin sınırlarının çizilmesini sağlamaktadır. Bu korumayı sağlamak için üç çeşit erişim belirteci (access modifier) kullanılmaktadır. Bunlar herkese açık (public), özel (private) ve koruma altında (protected) olarak söylenebilir. Miras Alma (Inheritance) Bir sınıftan, aralarında alt-üst ilişkisi olan başka sınıflar türetildiğinde, bu sınıflardaki metot ve özelliklerin ortaklaşa kullanılabilmesine imkân sağlayan mekanizmaya kalıtım denir. Mevcut bir sınıf üzerine başka sınıfların oluşturulmasını sağlar. Çok Biçimlilik (Polymorphism) Bir sınıftan türetilen başka bir sınıfın, türediği sınıfın tüm davranışlarını göstermek zorunda olmamasıdır. Türetilen sınıfın farklı davranışlar göstermesine çok biçimlilik denilmektedir. Farklı bir ifade ile, metotları ve türetilmiş sınıfları değişik şekillerde yeniden tanımlayabilmektir. Soyutlama (Abstraction) Alt sınıflarda tanımlanacak ortak özellikleri ve metotları taşıyacak bir üst sınıf düşünelim. Bu üst soyut sınıfın metotları, şablonlar olarak tanımlanabilir veya alt sınıfları tarafından üzerine yazılacak soyut metotlar olarak oluşturulabilir. Bir sınıf soyut metoda sahip ise otomatik olarak soyut hâle gelir ve soyut sınıflardan hiçbir nesne oluşturulamaz. C# ve .Net Platformu C# şeklinde yazılır ve “si şarp” diye okunmaktadır. C# programlama dili, Microsoft tarafından geliştirilmiş .Net platformunun bir ögesidir. C, C++ ve Java dillerinin en iyi yönleri alınarak, .Net platformu için tamamen nesne yönelimli bir dil olarak geliştirilmiştir. Java dilinden farkı ise C# da işaretçiler (pointer) kullanılabilmektedir. Böylece eski yazılım bileşenleri ile uyumlu bir şekilde çalışabilir. .Net Framework Diğer programlama dillerinden farklı olarak C# kodları, direk makine diline derlenmezler. Önce IL (Intermediate
Language) adı verilen bir ara kod formuna derlenirler. Derlenen ve uzantısı exe veya dll olan bu kodun dosyasına assembly adı verilir. Hazırlanan bu program çalıştırılmak istendiğine ise .Net Framework devreye girerek, IL kodunu makine koduna dönüştürerek, bilgisayarın anlayacağı şekle getirir. Yazılan bir C# programının çalışabilmesi için, bilgisayarda .Net framework kurulu olması gerekmektedir. .Net Framework, IL kodlarından oluşturduğu makine kodlarını tekrar kullanılabilmesi için, geçici bir süreliğine belleğe koyar. Böylece her seferinde IL kodundan makine koduna çevirim işlemi yapmayarak zamandan ve işlemci gücünden tasarruf eder. Program ilk çalıştırıldığında yavaş çalışırken belleğe alınan makine kodu yardımıyla diğer çalıştırmalarımızda daha hızlı çalışacaktır. CLR (Common Language Runtime)-Ortak Dil Çalışma Platformu .Net platformunda, işletim sistemi ile programlar arasında yer alan ve programların çalışmasını kontrol eden arabirime CLR denmektedir. Normalde programlar derlenerek makine diline çevrilirler ve işletim sistemiyle bağlantılı olarak çalışırlar. Yani Windows, Linux, MAC OS işletim sistemleri altyapıları gereği aynı programı çalıştıramazlar. Her bir platform için ayrı ayrı derlenerek çalışabilir hâle getirilmesi gerekir. .Net platformunda ise program kodu derlenerek IL (Intermediate Language)-Ara Dil’e çevrilir. Burada oluşturulan Assembly kodu, CLR tarafından herhangi bir işletim sisteminde çalıştırılabilir. IL kodu, JIT derleyici tarafından makine diline çevrilerek çalıştırılır. Just-In-Time Derleyicisi (JIT) Just-In-Time derleyicisi (JIT), herhangi bir .NET programlama dilinden bağımsız olarak .NET programlarının yürütülmesini yönetmekten sorumlu olan .NET’teki CLR’nin bir parçasıdır. Dile özgü bir derleyici, kaynak kodunu ara dile (IL) dönüştürür. Bu ara dil daha sonra JIT derleyicisi tarafından makine koduna dönüştürülür. Bu makine kodu, JIT derleyicisinin üzerinde çalıştığı bilgisayar ortamına özeldir. Neden C#? Microsoft tarafından geliştirilen C# programlama dili; yüksek verimli çalışması, kolay öğrenilebilmesi, nesne yönelimli programlamaya verdiği tam destek, Windows form mantığı desteği, gelişen internet teknolojilerine uyum sağlayabilmesi gibi belli başlı özellikleri yüzünden tercih edilmektedir. C# Kullanım Alanları C# dilinin çeşitli kullanım alanları mevcuttur. Bazıları:
• Konsol uygulamalarının geliştirilebilmesi
• Windows uygulamalarının geliştirilebilmesi
• Linux ve MacOs için uygulama geliştirilebilmesi
• Web servis desteği
• PDA, android, ios gibi mobil cihazlara uygun uygulama geliştirilebilmesi
• Veri analizleri
• ASP.Net web uygulamaları
• DLL hazırlama Geliştirme Ortamı Kurulumu C# geliştirme platformu kurulumu için, geliştireceğiniz uygulamaya ve işletim sistemine uygun olan en güncel versiyonunu https://visualstudio.microsoft.com/tr/ adresinden indirip kurabilirsiniz.