Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
oleh Scott Mitchell
Tutorial ini melihat kontrol ObjectDataSource Menggunakan kontrol ini Anda dapat mengikat data yang diambil dari BLL yang dibuat dalam tutorial sebelumnya tanpa harus menulis baris kode!
Pendahuluan
Dengan arsitektur aplikasi dan tata letak halaman situs web kami selesai, kami siap untuk mulai menjelajahi cara menyelesaikan berbagai tugas terkait data umum dan pelaporan. Dalam tutorial sebelumnya kita telah melihat cara mengikat data secara terprogram dari DAL dan BLL ke kontrol Web data di halaman ASP.NET. Sintaks ini menetapkan properti kontrol DataSource
Web data ke data yang akan ditampilkan lalu memanggil metode kontrol DataBind()
adalah pola yang digunakan dalam aplikasi ASP.NET 1.x, dan dapat terus digunakan dalam aplikasi 2.0 Anda. Namun, ASP.NET kontrol sumber data baru 2.0 menawarkan cara deklaratif untuk bekerja dengan data. Menggunakan kontrol ini Anda dapat mengikat data yang diambil dari BLL yang dibuat dalam tutorial sebelumnya tanpa harus menulis baris kode!
ASP.NET 2.0 dikirim dengan lima kontrol sumber data bawaan SqlDataSource, AccessDataSource, ObjectDataSource, XmlDataSource, dan SiteMapDataSource meskipun Anda dapat membangun kontrol sumber data kustom Anda sendiri, jika diperlukan. Karena kami telah mengembangkan arsitektur untuk aplikasi tutorial kami, kami akan menggunakan ObjectDataSource terhadap kelas BLL kami.
Gambar 1: ASP.NET 2.0 Menyertakan Lima Kontrol Sumber Data Built-In
ObjectDataSource berfungsi sebagai proksi untuk bekerja dengan beberapa objek lain. Untuk mengonfigurasi ObjectDataSource, kami menentukan objek yang mendasar ini dan bagaimana metodenya memetakan ke metode ObjectDataSource Select
, Insert
, Update
, dan Delete
. Setelah objek yang mendasar ini ditentukan dan metodenya dipetakan ke ObjectDataSource, kita kemudian dapat mengikat ObjectDataSource ke kontrol Web data. ASP.NET dilengkapi dengan banyak Kontrol Web Data, termasuk GridView, DetailsView, RadioButtonList, dan DropDownList, antara lain. Selama siklus hidup halaman, kontrol Web data mungkin perlu mengakses data yang terikat padanya, yang akan dicapainya dengan cara memanggil metode ObjectDataSource-nya Select
; jika kontrol Web data mendukung penyisipan, pembaruan, atau penghapusan, maka panggilan dapat dilakukan ke metode ObjectDataSource-nya Insert
, Update
, atau Delete
. Panggilan ini kemudian dirutekan oleh ObjectDataSource ke metode objek dasar yang sesuai seperti yang diilustrasikan diagram berikut.
Gambar 2: ObjectDataSource Berfungsi sebagai Proksi (Klik untuk melihat gambar ukuran penuh)
Meskipun ObjectDataSource dapat digunakan untuk memanggil metode untuk menyisipkan, memperbarui, atau menghapus data, mari kita fokus pada mengembalikan data; tutorial di masa mendatang akan menjelajahi menggunakan ObjectDataSource dan kontrol Web data yang memodifikasi data.
Langkah 1: Menambahkan dan Mengonfigurasi Kontrol ObjectDataSource
Mulailah dengan membuka SimpleDisplay.aspx
halaman di BasicReporting
folder, beralihlah ke tampilan Desain, lalu seret kontrol ObjectDataSource dari Kotak Alat ke permukaan desain halaman. ObjectDataSource muncul sebagai kotak abu-abu pada permukaan desain karena tidak menghasilkan markup apa pun; itu hanya mengakses data dengan memanggil metode dari objek tertentu. Data yang dikembalikan oleh ObjectDataSource dapat ditampilkan oleh kontrol Web data, seperti GridView, DetailsView, FormView, dan sebagainya.
Nota
Atau, Anda dapat terlebih dahulu menambahkan kontrol Web data ke halaman lalu, dari tag pintarnya, pilih <opsi Sumber> data baru dari daftar drop-down.
Untuk menentukan objek dasar ObjectDataSource dan bagaimana metode dari objek tersebut dipetakan ke ObjectDataSource, klik tautan Konfigurasikan Sumber Data dari tag pintar ObjectDataSource.
Gambar 3: Klik Tautan Konfigurasi Sumber Data dari Tag Cerdas (Klik untuk melihat gambar ukuran penuh)
Ini memunculkan wizard Konfigurasi Sumber Data. Pertama, kita harus menentukan objek yang akan dikerjakan oleh ObjectDataSource. Jika kotak centang "Perlihatkan hanya komponen data" dicentang, daftar drop-down di layar ini hanya mencantumkan objek yang telah dihiasi dengan DataObject
atribut . Saat ini daftar kami mencakup TableAdapters dalam Typed DataSet dan kelas BLL yang kami buat di tutorial sebelumnya. Jika Anda lupa menambahkan DataObject
atribut ke kelas Lapisan Logika Bisnis, Anda tidak akan melihatnya dalam daftar ini. Dalam hal ini, hapus centang pada kotak centang "Perlihatkan hanya komponen data" untuk melihat semua objek, yang harus menyertakan kelas BLL (bersama dengan kelas lain dalam Typed DataSet, DataTables, DataRows, dan sebagainya).
Dari layar pertama ini pilih ProductsBLL
kelas dari daftar drop-down dan klik Berikutnya.
Gambar 4: Tentukan Objek yang Akan Digunakan dengan Kontrol ObjectDataSource (Klik untuk melihat gambar ukuran penuh)
Layar berikutnya dalam wizard meminta Anda untuk memilih metode apa yang harus dipanggil ObjectDataSource. Menu drop-down mencantumkan metode yang mengembalikan data dalam objek yang dipilih dari layar sebelumnya. Di sini kita melihat GetProductByProductID
, , GetProducts
GetProductsByCategoryID
, dan GetProductsBySupplierID
. Pilih metode GetProducts
dari daftar drop-down dan klik Selesai (jika Anda menambahkan DataObjectMethodAttribute
ke metode ProductBLL
seperti yang ditunjukkan dalam tutorial sebelumnya, opsi ini akan dipilih secara default).
Gambar 5: Pilih Metode untuk Mengembalikan Data dari Tab SELECT (Klik untuk melihat gambar ukuran penuh)
Mengonfigurasi ObjectDataSource Secara Manual
Wizard Konfigurasi Sumber Data ObjectDataSource menawarkan cara cepat untuk menentukan objek yang digunakannya dan untuk mengaitkan metode objek apa yang dipanggil. Namun, Anda dapat mengonfigurasi ObjectDataSource melalui propertinya, baik melalui jendela Properti atau langsung di markup deklaratif. Cukup atur TypeName
properti ke jenis objek yang mendasar yang akan digunakan, dan SelectMethod
ke metode yang akan dipanggil saat mengambil data.
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
Bahkan jika Anda lebih suka wizard Konfigurasi Sumber Data mungkin ada kalanya Anda perlu mengonfigurasi ObjectDataSource secara manual, karena wizard hanya mencantumkan kelas yang dibuat pengembang. Jika Anda ingin mengikat ObjectDataSource ke kelas di .NET Framework seperti kelas Keanggotaan, untuk mengakses informasi akun pengguna, atau kelas Direktori untuk bekerja dengan informasi sistem file, Anda harus mengatur properti ObjectDataSource secara manual.
Langkah 2: Menambahkan Kontrol Web Data dan Mengikatnya ke ObjectDataSource
Setelah ObjectDataSource ditambahkan ke halaman dan dikonfigurasi, kami siap untuk menambahkan kontrol Web data ke halaman untuk menampilkan data yang dikembalikan oleh metode ObjectDataSource Select
. Kontrol Web data apa pun dapat terikat ke ObjectDataSource; mari kita lihat menampilkan data ObjectDataSource di GridView, DetailsView, dan FormView.
Mengikat GridView ke ObjectDataSource
Tambahkan kontrol GridView dari Kotak Alat ke permukaan desain SimpleDisplay.aspx
. Dari tag pintar GridView, pilih kontrol ObjectDataSource yang kami tambahkan di Langkah 1. Ini akan secara otomatis membuat BoundField di GridView untuk setiap properti yang dikembalikan oleh data dari metode ObjectDataSource Select
(yaitu, properti yang ditentukan oleh Products DataTable).
Gambar 6: GridView Telah Ditambahkan ke Halaman dan Terikat ke ObjectDataSource (Klik untuk melihat gambar ukuran penuh)
Anda kemudian dapat menyesuaikan, menyusun ulang, atau menghapus BoundFields GridView dengan mengklik opsi Edit Kolom dari tag pintar.
Gambar 7: Kelola BoundFields GridView Melalui Kotak Dialog Edit Kolom (Klik untuk melihat gambar ukuran penuh)
Luangkan waktu sejenak untuk memodifikasi BoundFields GridView, dengan menghapus ProductID
, SupplierID
, CategoryID
, QuantityPerUnit
, UnitsInStock
, UnitsOnOrder
, dan ReorderLevel
BoundFields. Cukup pilih BoundField dari daftar di kiri bawah dan klik tombol hapus (X merah) untuk menghapusnya. Selanjutnya, Susun ulang BoundFields sehingga CategoryName
dan SupplierName
BoundFields mendahului UnitPrice
BoundField dengan memilih BoundFields ini dan mengklik panah atas. Atur properti HeaderText
dari BoundFields yang tersisa menjadi Products
, Category
, Supplier
, dan Price
, masing-masing. Selanjutnya, formatlah BoundField Price
sebagai mata uang dengan mengatur properti BoundField HtmlEncode
ke false dan properti DataFormatString
ke {0:c}
. Terakhir, pindahkan Price
ke kanan dan tempatkan Discontinued
kotak centang di tengah menggunakan properti ItemStyle
/HorizontalAlign
.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="ProductName"
HeaderText="Product" SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName"
HeaderText="Category" ReadOnly="True"
SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName"
HeaderText="Supplier" ReadOnly="True"
SortExpression="SupplierName" />
<asp:BoundField DataField="UnitPrice"
DataFormatString="{0:c}" HeaderText="Price"
HtmlEncode="False" SortExpression="UnitPrice">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued">
<ItemStyle HorizontalAlign="Center" />
</asp:CheckBoxField>
</Columns>
</asp:GridView>
Gambar 8: BoundFields GridView Telah Disesuaikan (Klik untuk melihat gambar ukuran penuh)
Menggunakan Tema untuk Tampilan yang Konsisten
Tutorial ini berupaya menghapus pengaturan gaya tingkat kontrol apa pun dan menggunakan lembar gaya berjenjang yang ditentukan dalam file eksternal jika memungkinkan. File Styles.css
berisi DataWebControlStyle
kelas , HeaderStyle
, RowStyle
, dan AlternatingRowStyle
CSS yang harus digunakan untuk menentukan tampilan kontrol Web data yang digunakan dalam tutorial ini. Untuk mencapai hal ini, kita dapat mengatur properti CssClass
GridView ke DataWebControlStyle
, dan properti HeaderStyle
, RowStyle
, serta AlternatingRowStyle
sesuai dengan properti CssClass
.
Jika kita menetapkan properti ini CssClass
pada kontrol Web, kita perlu ingat untuk mengatur secara eksplisit nilai properti ini untuk setiap kontrol Web data yang ditambahkan ke tutorial kita. Pendekatan yang lebih mudah dikelola adalah menentukan properti terkait CSS default untuk kontrol GridView, DetailsView, dan FormView menggunakan Tema. Tema adalah kumpulan pengaturan properti tingkat kontrol, gambar, dan kelas CSS yang dapat diterapkan ke halaman di seluruh situs untuk menerapkan tampilan dan nuansa umum.
Tema kami tidak akan menyertakan gambar atau file CSS apa pun (kami akan meninggalkan stylesheet Styles.css
as-is, yang didefinisikan dalam folder akar aplikasi web), tetapi akan mencakup dua Skins. Skin adalah file yang menentukan properti default untuk kontrol Web. Secara khusus, kita akan memiliki file Skin untuk kontrol GridView dan DetailsView, yang menunjukkan properti terkait default CssClass
.
Mulailah dengan menambahkan File Kulit baru ke proyek Anda bernama GridView.skin
dengan mengklik kanan nama proyek di Penjelajah Solusi dan memilih Tambahkan Item Baru.
Gambar 9: Tambahkan File Kulit Bernama GridView.skin
(Klik untuk melihat gambar ukuran penuh)
File kulit perlu ditempatkan dalam Tema, yang terletak di App_Themes
folder . Karena kami belum memiliki folder seperti itu, Visual Studio akan dengan ramah menawarkan untuk membuatnya untuk kami saat menambahkan Skin pertama kami. Klik Ya untuk membuat App_Theme
folder dan menempatkan file baru GridView.skin
di sana.
Gambar 10: Biarkan Visual Studio Membuat App_Theme
Folder (Klik untuk melihat gambar ukuran penuh)
Ini akan membuat Tema baru di App_Themes
folder bernama GridView dengan file GridView.skin
Skin .
Gambar 11: Tema GridView Telah Ditambahkan ke App_Theme
Folder
Ganti nama Tema GridView menjadi DataWebControls (klik kanan pada folder GridView di App_Theme
folder dan pilih Ganti Nama). Selanjutnya, masukkan markup berikut ke GridView.skin
dalam file:
<asp:GridView runat="server" CssClass="DataWebControlStyle">
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
<RowStyle CssClass="RowStyle" />
<HeaderStyle CssClass="HeaderStyle" />
</asp:GridView>
Ini menentukan properti default untuk properti terkait CssClass
pada setiap GridView di halaman mana pun yang menggunakan Tema DataWebControls. Mari kita tambahkan Skin lain untuk DetailsView, kontrol Web data yang akan segera kita gunakan. Tambahkan Skin baru ke Tema DataWebControls bernama DetailsView.skin
dan tambahkan markup berikut:
<asp:DetailsView runat="server" CssClass="DataWebControlStyle">
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
<RowStyle CssClass="RowStyle" />
<FieldHeaderStyle CssClass="HeaderStyle" />
</asp:DetailsView>
Dengan Tema yang ditentukan, langkah terakhir adalah menerapkan Tema ke halaman ASP.NET kami. Tema dapat diterapkan berdasarkan halaman demi halaman atau untuk semua halaman di situs web. Mari kita gunakan tema ini untuk semua halaman di situs web. Untuk mencapai hal ini, tambahkan markup berikut ke bagian Web.config
dari <system.web>
:
<pages styleSheetTheme="DataWebControls" />
Hanya itu saja!
styleSheetTheme
Pengaturan menunjukkan bahwa properti yang ditentukan dalam Tema tidak boleh mengambil alih properti yang ditentukan pada tingkat kontrol. Untuk menentukan bahwa pengaturan tema harus menggantikan pengaturan kontrol, gunakan atribut theme
sebagai ganti styleSheetTheme
; sayangnya, pengaturan tema yang ditentukan melalui atribut theme
tidak muncul dalam tampilan Desain Visual Studio. Lihat Gambaran Umum Tema dan Kulit ASP.NET dan Gaya Menggunakan TemaServer-Side untuk informasi lebih lanjut tentang Tema dan Kulit; lihat Cara: Menerapkan Tema ASP.NET untuk informasi lebih lanjut tentang mengonfigurasi halaman untuk menggunakan tema.
Gambar 12: GridView Menampilkan Nama Produk, Kategori, Pemasok, Harga, dan Informasi yang Dihentikan (Klik untuk melihat gambar ukuran penuh)
Menampilkan Satu Rekaman Sekaligus di Tampilan Detail
GridView menampilkan satu baris untuk setiap rekaman yang dikembalikan oleh sumber data yang terhubung. Namun, ada kalanya kita mungkin ingin menampilkan rekaman satu per satu atau hanya satu rekaman pada satu waktu.
Kontrol DetailsView menawarkan fungsionalitas ini, penyajian sebagai HTML <table>
dengan dua kolom dan satu baris untuk setiap kolom atau properti yang terikat ke kontrol. Anda dapat menganggap DetailsView sebagai GridView dengan satu rekaman diputar 90 derajat.
Mulailah dengan menambahkan kontrol DetailsView di atas GridView di SimpleDisplay.aspx
. Selanjutnya, ikat ke kontrol ObjectDataSource yang sama dengan GridView. Seperti halnya GridView, BoundField akan ditambahkan ke DetailsView untuk setiap properti dalam objek yang dikembalikan oleh metode ObjectDataSource Select
. Satu-satunya perbedaan adalah bahwa BoundFields DetailsView ditata secara horizontal daripada secara vertikal.
Gambar 13: Tambahkan DetailsView ke Halaman dan Dihubungkan ke ObjectDataSource (Klik untuk melihat gambar ukuran penuh)
Seperti GridView, BoundFields milik DetailsView dapat disesuaikan untuk memberikan tampilan data yang lebih sesuai dengan kebutuhan, yang berasal dari ObjectDataSource. Gambar 14 menunjukkan DetailsView setelah BoundFields dan CssClass
propertinya telah dikonfigurasi untuk membuat tampilannya mirip dengan contoh GridView.
Gambar 14: Tampilan Detail Menampilkan Satu rekaman (Klik untuk melihat gambar ukuran penuh)
Perhatikan bahwa DetailsView hanya menampilkan rekaman pertama yang dikembalikan oleh sumber datanya. Untuk memungkinkan pengguna menelusuri semua rekaman, satu per satu, kita harus mengaktifkan fungsi paging untuk DetailsView. Untuk melakukannya, kembali ke Visual Studio dan centang kotak aktifkan Halaman di tag pintar DetailsView.
Gambar 15: Aktifkan Halaman di DetailsView Control (Klik untuk melihat gambar ukuran penuh)
Gambar 16: Dengan Paging Aktif, DetailsView Memungkinkan Pengguna Melihat Semua Produk (Klik untuk melihat gambar ukuran penuh)
Kita akan berbicara lebih banyak tentang penomoran dalam tutorial di masa mendatang.
Tata Letak yang Lebih Fleksibel untuk Menampilkan Satu Rekaman dalam Satu Waktu
DetailsView cukup kaku dalam cara menampilkan setiap rekaman yang dikembalikan dari ObjectDataSource. Kami mungkin menginginkan tampilan data yang lebih fleksibel. Misalnya, daripada menunjukkan nama produk, kategori, pemasok, harga, dan informasi yang dihentikan masing-masing pada baris terpisah, kami mungkin ingin menunjukkan nama produk dan harga dalam <h4>
judul, dengan kategori dan informasi pemasok muncul di bawah nama dan harga dalam ukuran font yang lebih kecil. Dan kami mungkin tidak peduli untuk menunjukkan nama properti (Produk, Kategori, dan sebagainya) di samping nilai.
Kontrol FormView menyediakan tingkat kustomisasi ini. Daripada menggunakan bidang (seperti GridView dan DetailsView lakukan), FormView menggunakan templat, yang memungkinkan campuran kontrol Web, HTML statis, dan sintaks pengikatan data. Jika Anda terbiasa dengan kontrol Repeater dari ASP.NET 1.x, Anda dapat menganggap FormView sebagai Pengulang untuk menampilkan satu rekaman.
Tambahkan kontrol FormView ke SimpleDisplay.aspx
permukaan desain halaman. Awalnya FormView ditampilkan sebagai blok abu-abu, memberi tahu kami bahwa minimal kita perlu menyediakan kontrol ItemTemplate
.
Gambar 17: FormView Harus Menyertakan ItemTemplate
(Klik untuk melihat gambar ukuran penuh)
Anda dapat mengikat FormView langsung ke kontrol sumber data melalui tag pintar FormView, yang akan membuat default ItemTemplate
secara otomatis (bersama dengan EditItemTemplate
dan InsertItemTemplate
, jika kontrol InsertMethod
dan UpdateMethod
properti ObjectDataSource diatur). Namun, untuk contoh ini mari kita ikat data ke FormView dan tentukan ItemTemplate
secara manual. Mulailah dengan mengatur properti FormView DataSourceID
ke ID
kontrol ObjectDataSource, ObjectDataSource1
. Selanjutnya, buat ItemTemplate
sehingga menampilkan nama dan harga produk dalam <h4>
elemen dan kategori dan nama pengirim di bawahnya dalam ukuran font yang lebih kecil.
<asp:FormView ID="FormView1" runat="server"
DataSourceID="ObjectDataSource1" EnableViewState="False">
<ItemTemplate>
<h4><%# Eval("ProductName") %>
(<%# Eval("UnitPrice", "{0:c}") %>)</h4>
Category: <%# Eval("CategoryName") %>;
Supplier: <%# Eval("SupplierName") %>
</ItemTemplate>
</asp:FormView>
Gambar 18: Produk Pertama (Chai) Ditampilkan dalam Format Kustom (Klik untuk melihat gambar ukuran penuh)
Ini adalah sintaks pengikatan data <%# Eval(propertyName) %>
. Metode Eval
mengembalikan nilai properti yang ditentukan untuk objek saat ini yang terikat ke kontrol FormView. Lihat artikel Alex Homer Sintaks Pengikatan Data yang Disederhanakan dan Diperluas di ASP.NET 2.0 untuk informasi selengkapnya tentang seluk beluk pengikatan data.
Seperti DetailsView, FormView hanya menampilkan rekaman pertama yang dikembalikan dari ObjectDataSource. Anda dapat mengaktifkan fitur halaman di FormView untuk memungkinkan pengunjung menavigasi produk satu per satu.
Ringkasan
Mengakses dan menampilkan data dari Lapisan Logika Bisnis dapat dicapai tanpa menulis baris kode berkat kontrol ObjectDataSource ASP.NET 2.0. ObjectDataSource memanggil metode kelas tertentu dan mengembalikan hasilnya. Hasil ini dapat ditampilkan dalam kontrol Web data yang terikat ke ObjectDataSource. Dalam tutorial ini kita melihat pengikatan kontrol GridView, DetailsView, dan FormView ke ObjectDataSource.
Sejauh ini kita hanya melihat cara menggunakan ObjectDataSource untuk memanggil metode tanpa parameter, tetapi bagaimana jika kita ingin memanggil metode yang mengharapkan parameter input, seperti ProductBLL
kelas GetProductsByCategoryID(categoryID)
? Untuk memanggil metode yang mengharapkan satu atau beberapa parameter, kita harus mengonfigurasi ObjectDataSource untuk menentukan nilai untuk parameter ini. Kita akan melihat cara mencapai ini dalam tutorial berikutnya.
Selamat Pemrograman!
Bacaan Lebih Lanjut
Untuk informasi selengkapnya tentang topik yang dibahas dalam tutorial ini, lihat sumber daya berikut:
- Membuat Kontrol Sumber Data Anda Sendiri
- Contoh GridView untuk ASP.NET 2.0
- Tema dalam ASP.NET 2.0
- GayaServer-Side Menggunakan Tema
- Cara: Menerapkan Tema ASP.NET Secara Terprogram
Tentang Penulis
Scott Mitchell, penulis tujuh buku ASP/ASP.NET dan pendiri 4GuysFromRolla.com, telah bekerja sama dengan teknologi Microsoft Web sejak 1998. Scott bekerja sebagai konsultan, pelatih, dan penulis independen. Buku terbarunya adalah Sams Teach Yourself ASP.NET 2.0 dalam 24 Jam. Dia dapat dijangkau di mitchell@4GuysFromRolla.com.
Ucapan terima kasih khusus kepada
Seri tutorial ini ditinjau oleh banyak peninjau yang bermanfaat. Peninjau utama untuk tutorial ini adalah Hilton Giesenow. Tertarik untuk meninjau artikel MSDN saya yang akan datang? Jika demikian, hubungi saya di mitchell@4GuysFromRolla.com.