Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. CloudKit
Code

Membuat Aplikasi Daftar Belanja dengan CloudKit: Menambahkan Catatan

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Building a Shopping List Application With CloudKit.
Building a Shopping List Application With CloudKit: Introduction
Building a Shopping List Application With CloudKit: Adding Relationships

Indonesian (Bahasa Indonesia) translation by Primrose (you can also view the original English article)

Dalam tutorial pertama dari seri ini, kita menjelajahi kerangka kerja dan infrastruktur CloudKit. Kit juga meletakkan dasar untuk aplikasi contoh yang akan kita bangun, aplikasi daftar belanja. Dalam tutorial ini, kita berfokus untuk menambahkan, mengedit, dan menghapus daftar belanja.

Prasyarat

Seperti yang saya sebutkan di tutorial sebelumnya, saya akan menggunakan Xcode 7 dan Swift 2. Jika Anda menggunakan Xcode versi lama, maka perlu diingat bahwa Anda menggunakan versi bahasa pemrograman Swift yang berbeda.

Dalam tutorial ini, kami akan terus bekerja dengan proyek yang kami buat di tutorial pertama. Anda dapat mengunduhnya dari GitHub.

1. Menyiapkan CocoaPods

Aplikasi daftar belanja akan menggunakan perpustakaan SVProgressHUD, perpustakaan populer yang dibuat oleh Sam Vermette yang membuatnya mudah untuk menampilkan indikator kemajuan. Anda dapat menambahkan perpustakaan secara manual ke proyek Anda, tetapi saya sangat menyarankan menggunakan CocoaPods untuk mengelola dependensi. Apakah Anda baru mengenal CocoaPods? Saya telah menulis tutorial pengantar untuk CocoaPods yang akan membantu Anda mendapatkan kecepatan.

Langkah 1: Membuat Podfile

Buka Finder dan arahkan ke akar proyek Xcode Anda. Buat file baru, beri nama Podfile, dan tambahkan baris Ruby berikut ini.

The first line specifies the platform, iOS, and the project's deployment target, iOS 8.0. Baris kedua penting jika Anda menggunakan Swift. Swift tidak mendukung pustaka statis, tetapi CocoaPods menyediakan opsi ini sejak versi 0,36 untuk menggunakan kerangka kerja. Kami kemudian menentukan dependensi untuk target Daftar proyek. Ganti Daftar dengan nama target Anda jika target Anda diberi nama berbeda.

Langkah 2: Memasang Ketergantungan

Buka Terminal, arahkan ke akar proyek Xcode Anda, dan jalankan pod install. Ini akan melakukan sejumlah hal untuk Anda, seperti menginstal dependensi yang ditentukan dalam Podfile dan membuat ruang kerja Xcode.

Setelah menyelesaikan pengaturan CocoaPods, tutup proyek dan buka ruang kerja CocoaPods yang dibuat untuk Anda. Yang terakhir ini sangat penting. Buka ruang kerja, bukan proyek. Ruang kerja mencakup dua proyek, proyek Daftar dan proyek bernama Pods.

2. Mendata Daftar Belanja

Langkah 1: Rumah tangga

Kami siap untuk memfokuskan kembali pada kerangka CloudKit. Namun, pertama-tama, kita perlu melakukan pembersihan dengan mengganti nama kelas ViewController ke kelas ListsViewController.

Mulailah dengan mengganti nama ViewController.swift ke ListsViewController.swift. Buka ListsViewController.swift dan ubah nama kelas ViewController ke kelas ListsViewController.

Selanjutnya, buka Main.storyboard, luaskan View Controller Scene dalam Outline Dokumen di sebelah kiri dan pilih View Controller. Buka  Identity Inspector di sebelah kanan dan ubah Class ke ListsViewController.

Langkah 2: Menambahkan tampilan tabel

Ketika pengguna membuka aplikasi, itu disajikan dengan daftar belanja mereka. Kami akan menampilkan daftar belanja dalam tampilan tabel. Mari kita mulai dengan mengatur antarmuka pengguna. Pilih Lists View Controller di Lists View Controller Scene dan pilih Embed In> Navigation Controller dari menu Editor Xcode.

Tambahkan tampilan tabel ke tampilan pengontrol tampilan dan buat batasan tata letak yang diperlukan untuknya. Dengan tampilan tabel yang dipilih, buka Attributes Inspector dan setel Prototype Cells ke 1. Pilih sel prototipe dan atur Style ke Basic dan Identifier ke ListCell.

Dengan tampilan tabel dipilih, buka Connections Inspector. Hubungkan data tampilan tabel dataSource dan delegate outlet ke Lists View Controller.

Langkah 3: Bagian Kosong

Meskipun kami hanya membuat contoh aplikasi untuk menggambarkan bagaimana CloudKit berfungsi, saya ingin menampilkan pesan jika ada yang salah atau jika tidak ada daftar belanja ditemukan di iCloud. Tambahkan label ke pengontrol tampilan, menjadikannya sebesar tampilan pengontrol tampilan, buat batasan tata letak yang diperlukan untuknya, dan pusatkan teks label.

Karena kita sedang berhadapan dengan permintaan jaringan, saya juga ingin menampilkan tampilan indikator aktivitas selama aplikasi menunggu tanggapan dari iCloud. Tambahkan tampilan indikator aktivitas ke tampilan pengontrol tampilan dan pusatkan dalam tampilan induknya. Di Attributes Inspector, centang kotak centang berlabel Hides When Stopped.

Lists View Controller

Langkah 4: Menghubungkan Outlet

Buka ListsViewController.swift dan nyatakan outlet untuk label, tampilan tabel, dan tampilan indikator aktivitas. Ini juga saat yang tepat untuk membuat kelas ListsViewController sesuai dengan protokol UITableViewDataSource dan UITableViewDelegate.

Perhatikan bahwa saya juga menambahkan pernyataan impor untuk kerangka kerja SVProgressHUD dan bahwa saya telah mendeklarasikan konstanta statis untuk pengenal penggunaan kembali sel prototipe yang kami buat di storyboard.

Kembali ke storyboard dan hubungkan outlet dengan pandangan yang terkait dalam Lists View Controller Scene.

Langkah 5: Mempersiapkan Tampilan Tabel

Sebelum kami mengambil data dari iCloud, kami perlu memastikan tampilan tabel siap untuk menampilkan data. Pertama-tama kita perlu membuat properti, lists, untuk menyimpan rekaman yang akan kita ambil. Ingat bahwa catatan adalah contoh kelas CKRecord Ini berarti properti yang akan menyimpan data dari iCloud adalah tipe [CKRecord], sebuah array dari instance CKRecord.

Untuk memulai, kita perlu mengimplementasikan tiga metode protokol UITableViewDataSource:

  • numberOfSectionsInTableView(_:)
  • numberOfRowsInSection(_:)
  • cellForRowAtIndexPath(_:)

Jika Anda memiliki pengalaman bekerja dengan tampilan tabel, maka penerapan masing-masing metode ini sangat mudah. Namun, cellForRowAtIndexPath (_ :) mungkin memerlukan beberapa penjelasan. Ingat bahwa instance CKRecord adalah kamus pasangan nilai-kunci supercharged. Untuk mengakses nilai kunci tertentu, Anda memanggil objectForKey (_ :) pada objek CKRecord. Itulah yang kita lakukan di cellForRowAtIndexPath (_ :). Kami mengambil catatan yang sesuai dengan baris tampilan tabel dan menanyakannya untuk nilai "name" kunci. Jika pasangan kunci-nilai tidak ada, kami menampilkan tanda pisah untuk menunjukkan daftar belum memiliki nama.

Langkah 6: Mempersiapkan Antarmuka Pengguna

Ada satu langkah lagi untuk kami ambil, siapkan antarmuka pengguna. Dalam metode viewDidLoad view controller, hapus panggilan metode fetchUserRecordID dan aktifkan setupView, metode helper.

Metode setupView menyiapkan antarmuka pengguna untuk mengambil daftar catatan. Kami menyembunyikan label dan tampilan tabel, dan memberi tahu tampilan indikator aktivitas untuk mulai menjiwai.

Bangun dan jalankan aplikasi di perangkat atau di Simulator iOS. Jika Anda telah mengikuti langkah-langkah di atas, Anda akan melihat tampilan kosong dengan tampilan indikator aktivitas berputar di tengah.

Busy Pretending to Be Fetching Data

Langkah 7: Membuat Jenis Rekaman

Sebelum kami mengambil catatan apa pun, kami perlu membuat jenis catatan untuk daftar belanja di dasbor CloudKit. Dasbor CloudKit adalah aplikasi web yang memungkinkan pengembang mengelola data yang disimpan di server iCloud Apple

Pilih proyek di Project Navigator dan pilih target List dari daftar target. Buka tab Capabilities di bagian atas dan rentangkan bagian iCloud. Di bawah daftar penampung iCloud, klik tombol yang berlabel CloudKit Dashboard.

Open CloudKit Dashboard

Masuk dengan akun pengembang Anda dan pastikan aplikasi Lists dipilih di kiri atas. Di sebelah kiri, pilih Record Types dari bagian Schema Setiap aplikasi secara default memiliki tipe catatan Pengguna. Untuk membuat tipe catatan baru, klik tombol plus di bagian atas kolom ketiga. Kami akan mengikuti konvensi penamaan Apple dan menamai Lists jenis rekaman, bukan Lists.

Adding a New Record Type

Perhatikan bahwa bidang pertama secara otomatis dibuat untuk Anda. Atur Field Name untuk name dan verifikasi bahwa Field Type diatur ke String. Jangan lupa klik tombol Save di bagian bawah untuk membuat tipe catatan Lists. Kami akan mengunjungi kembali Dasbor CloudKit nanti dalam seri ini.

Langkah 8: Melakukan Query

Dengan jenis catatan Lists dibuat, akhirnya waktu untuk mengambil beberapa catatan dari iCloud. Kerangka CloudKit menyediakan dua API untuk berinteraksi dengan iCloud, API kenyamanan, dan API berdasarkan kelas NSOperation. Kita akan menggunakan kedua API dalam seri ini, tetapi kami akan membuatnya tetap sederhana untuk saat ini dan menggunakan API kenyamanan.

Di Xcode, buka ListsViewController.swift dan aktifkan metode fetchLists di viewDidLoad. Metode fetchLists adalah metode pembantu lain. Mari kita lihat penerapan metode.

Karena catatan daftar belanja disimpan dalam basis data pribadi pengguna, pertama-tama kita mendapatkan referensi ke basis data pribadi penampung default. Untuk mengambil daftar belanja pengguna, kita perlu melakukan kueri pada basis data pribadi, menggunakan kelas CKQuery.

Kami menginisialisasi turunan CKQuery dengan menjalankan init (recordType: predicate :) initializer yang ditunjuk, meneruskan tipe record dan objek NSPredicate. Untuk menghindari salah ketik, saya telah membuat konstanta untuk jenis rekaman. Konstanta, RecordTypeLists, dideklarasikan di bagian atas ListsViewController.swift.

Sebelum kami mengeksekusi query, kami mengatur properti query sortDescriptors Kami membuat larik yang berisi objek NSSortDescriptor dengan "name" kunci dan set menaik ke true.

Menjalankan kueri sederhana seperti memanggil performQuery (_: inZoneWithID: completionHandler :) pada privateDatabase, meneruskan query sebagai argumen pertama. Parameter kedua menentukan identifier dari zona rekaman tempat kueri akan dilakukan. Dengan melewatkan nil, query dilakukan pada zona default dari database.

Argumen ketiga adalah penangan penyelesaian. Penutupan menerima array opsional objek CKRecord dan instance NSError opsional. Dokumentasi CloudKit secara eksplisit menyebutkan bahwa handler penyelesaian dapat dipanggil dari sembarang utas. Oleh karena itu kami mengirimkan pemrosesan tanggapan ke utas utama dengan membungkus prosesResponseForQuery (_: error :) metode panggilan dalam penutupan dispatch_async. Begitulah cara mudahnya melakukan kueri. Mari kita lihat bagaimana kami menangani respons kueri.

Langkah 9: Memproses Respons

Implementasi processResponseForQuery (_: error :) tidak sulit jika Anda terbiasa dengan bahasa Swift. Kami memeriksa isi catatan dan parameter kesalahan, dan memperbarui variabel pesan yang sesuai.

Di akhir metode, kami menjalankan updateView. Dalam metode pembantu ini, kami memperbarui antarmuka pengguna berdasarkan konten properti lists.

Bangun dan jalankan aplikasi untuk menguji apa yang sudah kami dapatkan sejauh ini. Saat ini kami tidak memiliki catatan, tetapi kami akan memperbaikinya di bagian selanjutnya dari tutorial ini.

No Records Found

3. Menambahkan Daftar Belanja

Langkah 1: Membuat Kelas AddListViewController

Karena menambahkan dan mengedit daftar belanja sangat mirip, kami akan menerapkan keduanya pada saat yang bersamaan. Buat file baru dan beri nama AddListViewController.swift. Buka file yang baru dibuat dan buat subclass UIViewController bernama AddListViewController. Di bagian atas, tambahkan pernyataan impor untuk kerangka UIKit, CloudKit, dan SVProgressHUD. Deklarasikan dua outlet, salah satu tipe UITextField! dan salah satu dari jenis UIBarButtonItem !. Yanga tidak kalah penting, buat dua tindakan, cancel (_ :) dan save (_ :).

Langkah 2: Membuat Antarmuka Pengguna

Buka Main.storyboard dan tambahkan pengontrol tampilan ke storyboard. Dengan pengontrol tampilan dipilih, buka Identity Inspector di sebelah kanan dan atur Class ke AddListViewController

Pengguna akan dapat menavigasi ke pengontrol tampilan daftar add dengan mengetuk tombol di pengontrol tampilan daftar. Seret item tombol bar dari Object Library ke bilah navigasi dari lists view controller. Dengan item tombol bar dipilih, buka  Attributes Inspector dan setel System Item ke Add. Tekan Control dan seret dari item tombol bar ke pengontrol tampilan daftar add dan pilih push dari menu yang muncul.

Sangat penting bahwa Anda memilih push dari bagian Action Segue. Ini harus menjadi item pertama di menu. Pilih segue yang Anda buat dan atur Identifier ke ListDetail di Attributes Inspector di sebelah kanan.

Tambahkan dua item tombol bar ke bilah navigasi dari pengontrol tampilan daftar add, satu di kiri dan satu di sebelah kanan. Setel Item Sistem dari item tombol bilah kiri menjadi Cancel dan tombol pilihan tombol kanan ke Save. Akhirnya, tambahkan kolom teks ke controller tampilan daftar add. Pusatkan bidang teks dan atur Alignment-nya ke pusat di Attributes Inspector.

Add List View Controller

Ada kemungkinan bahwa, setelah membuat segue dari pengendali tampilan daftar ke pengontrol tampilan daftar tambahan, tidak ada item navigasi yang dibuat untuk Add List View Controller Scene. Saya yakin ini adalah bug di Xcode 7.

Untuk mengatasi masalah ini, pilih segue dan, di Attributes Inspector, tetapkan Segue ke Deprecated Segues > Push. Ini akan menambahkan item navigasi ke TKP. Selanjutnya, atur Segue kembali ke Adaptive Segues> Show.

Akhirnya, hubungkan outlet dan tindakan yang Anda buat di AddListViewController.swift ke elemen antarmuka pengguna yang sesuai di layar.

Langkah 3: Protokol AddListViewControllerDelegate

Sebelum kita mengimplementasikan kelas AddListViewController, kita perlu mendeklarasikan protokol yang akan kita gunakan untuk berkomunikasi dari pengontrol tampilan daftar add ke pengendali tampilan daftar. Protokol mendefinisikan dua metode, satu untuk menambahkan dan satu untuk memperbarui daftar belanja. Seperti inilah protokol itu.

Kami juga perlu menyatakan tiga properti, satu untuk delegasi, satu untuk daftar belanja yang dibuat atau diperbarui, dan variabel pembantu yang menunjukkan apakah kami membuat daftar belanja baru atau mengedit catatan yang sudah ada.

Implementasi kelas AddListViewController bukanlah ilmu roket. Metode yang terkait dengan siklus hidup tampilan adalah singkat dan mudah dimengerti. Di viewDidLoad, pertama kita memanggil metode penolong setupView. Kami akan menerapkan metode ini sebentar lagi. Kami kemudian memperbarui nilai variabel helper newList berdasarkan nilai properti lists. Jika lists sama dengan nil, maka kita tahu bahwa kita sedang membuat catatan baru. Di viewDidLoad, kami juga menambahkan pengontrol tampilan sebagai pengamat untuk pemberitahuan UITextFieldTextDidChangeNotification.

Di viewDidAppear (_ :), kita memanggil becomeFirstResponder di bidang teks untuk menyajikan keyboard kepada pengguna.

Di setupView, kita memanggil dua metode pembantu, updateNameTextField dan updateSaveButton. Di updateNameTextField, kami mengisi bidang teks jika lists tidak nil. Dengan kata lain, jika kita mengedit rekaman yang sudah ada, maka kita mengisi bidang teks dengan nama rekaman itu.

Metode updateSaveButton bertugas mengaktifkan dan menonaktifkan item tombol bar di kanan atas. Kita hanya mengaktifkan tombol simpan jika nama daftar belanja bukan string kosong.

Langkah 4: Menerapkan Tindakan

cancel(_:) tindakan sesederhana yang didapatkannya. Kita memunculkan pengontrol tampilan atas dari susunan navigasi. Save (_ :) action lebih menarik. Dalam metode ini, kita mengekstrak input pengguna dari kolom teks dan mendapatkan referensi ke basis data pribadi kontainer standar.

Jika kita menambahkan daftar belanja baru, maka kita membuat contoh CKRecord baru dengan memohon init (recordType :), meneruskan RecordTypeLists sebagai tipe catatan. Kami kemudian memperbarui nama daftar belanja dengan menetapkan nilai catatan untuk "name" kunci.

Karena menyimpan catatan melibatkan permintaan jaringan dan dapat mengambil jumlah waktu yang tidak sepele, kami menunjukkan indikator kemajuan. Untuk menyimpan catatan baru atau perubahan apa pun pada rekaman yang sudah ada, kami memanggil saveRecord (_: completionHandler :) pada privateDatabase, meneruskan catatan sebagai argumen pertama. Argumen kedua adalah penangan penyelesaian lain yang dipanggil saat menyimpan catatan selesai, berhasil atau tidak berhasil.

Handler penyelesaian menerima dua argumen, CKRecord opsional dan NSError opsional. Seperti yang saya sebutkan sebelumnya, handler penyelesaian dapat dipanggil pada sembarang thread, yang berarti kita perlu mengkodekannya. Kami melakukan ini dengan secara eksplisit menerapkan metode processResponse (_: error :) pada utas utama.

Dalam processResponse (_: error :), kami memverifikasi jika kesalahan dilemparkan. Jika kami mengalami masalah, kami menampilkan peringatan kepada pengguna. Jika semuanya berjalan lancar, kami memberi tahu delegasi dan menampilkan pengontrol tampilan dari tumpukan navigasi.

Yang tidak kalah penting, ketika pengontrol tampilan menerima pemberitahuan UITextFieldTextDidChangeNotification, itu akan memanggil updateSaveButton untuk memperbarui tombol simpan.

Langkah 5: Mengikat Semuanya Bersama

Di kelas ListsViewController, kita masih perlu memperhatikan beberapa hal. Mari kita mulai dengan menyesuaikan kelas ke protokol AddListViewControllerDelegate.

Ini juga berarti bahwa kita perlu menerapkan metode protokol AddListViewControllerDelegate. Dalam metode controller (_: didAddList :), kami menambahkan catatan baru ke array objek CKRecord. Kita kemudian mengurutkan berbagai catatan, memuat ulang tampilan tabel, dan menjalankan updateView pada pengontrol tampilan.

Metode sortLists cukup mendasar. Kami memanggil sortInPlace pada larik rekaman, menyortir larik berdasarkan nama rekaman.

Implementasi metode kedua dari protokol AddListViewControllerDelegate, controller (_: didUpdateList :), terlihat hampir identik. Karena kita tidak menambahkan catatan, kita hanya perlu mengurutkan berbagai rekaman dan memuat ulang tampilan tabel. Tidak perlu memanggil updateView pada pengontrol tampilan karena larik rekaman secara definisi tidak kosong.

Untuk mengedit rekaman, pengguna perlu mengetuk tombol aksesori pada baris tampilan tabel. Ini berarti bahwa kita perlu menerapkan metode tableView (_: accessoryButtonTappedForRowWithIndexPath :) dari protokol UITableViewDelegate. Sebelum kita menerapkan metode ini, nyatakan properti pembantu, selection, untuk menyimpan pilihan pengguna

Di tableView (_: accessoryButtonTappedForRowWithIndexPath :), kami menyimpan pilihan pengguna dalam selection dan memberi tahu pengontrol tampilan untuk melakukan segue yang mengarah ke pengontrol tampilan daftar add. Jika Anda penasaran, saya telah membuat konstanta dalam ListsViewController.swift untuk pengenal segue, SegueListDetail.

Kita hampir sampai. Ketika segue dengan identifier ListDetail dilakukan, kita perlu mengkonfigurasi contoh AddListViewController yang didorong ke susunan navigasi. Kita melakukan ini di prepareForSegue (_: sender :?).

Segue memberikan referensi kepada pengendali tampilan tujuan, contoh AddListViewController. Kita mengatur properti delegate, dan, jika daftar belanja diperbarui, kami mengatur properti lists pengendali tampilan ke catatan yang dipilih.

Bangun dan jalankan aplikasi untuk melihat hasilnya. Anda sekarang dapat menambahkan daftar belanja baru dan mengedit nama daftar belanja yang ada.

4. Menghapus Daftar Belanja

Menambahkan kemampuan untuk menghapus daftar belanja tidak banyak pekerjaan ekstra. Pengguna harus dapat menghapus daftar belanja dengan menggesek baris tampilan tabel dari kanan ke kiri dan mengetuk tombol hapus yang terungkap. Untuk memungkinkan hal ini, kita perlu menerapkan dua metode lagi dari protokol UITableViewDataSource:

  • tableView (_: canEditRowAtIndexPath :)
  • tableView(_:commitEditingStyle:forRowAtIndexPath:)

Implementasi tableView (_: canEditRowAtIndexPath :) sepele seperti yang Anda lihat di bawah ini.

Dalam tableView (_: commitEditingStyle: forRowAtIndexPath :), kami mengambil catatan yang benar dari larik rekaman dan menjalankan deleteRecord (_ :) pada pengontrol tampilan, meneruskan catatan yang perlu dihapus.

Metode deleteRecord (_ :) akan terlihat akrab sekarang. Kami menunjukkan indikator progres dan memanggil deleteRecordWithID (_: completionHandler :) pada basis data pribadi kontainer standar. Perhatikan bahwa kita melewati pengenal catatan, bukan catatan itu sendiri. Handler penyelesaian menerima dua argumen, opsional CKRecordID dan NSError opsional.

Dalam handler penyelesaian, kami mengabaikan indikator progres dan memanggil processResponseForDeleteRequest (_: recordID: error :) pada utas utama. Dalam metode ini, kami memeriksa nilai-nilai recordID dan error yang telah diberikan CloudKit API kepada kami dan kami memperbarui message yang sesuai. Jika permintaan penghapusan berhasil, maka kami memperbarui antarmuka pengguna dan larik rekaman.

Itu dia Saatnya menguji aplikasi dengan benar dengan beberapa data. Jalankan aplikasi di perangkat atau di Simulator iOS dan tambahkan beberapa daftar belanja. Anda harus bisa menambahkan, mengedit, dan menghapus daftar belanja.

Kesimpulan

Meskipun artikel ini cukup panjang, perlu diingat bahwa kami hanya sebentar berinteraksi dengan API CloudKit. API kenyamanan dari framework CloudKit ringan dan mudah digunakan.

Tutorial ini, bagaimanapun, juga menggambarkan bahwa pekerjaan Anda sebagai pengembang tidak terbatas untuk berinteraksi dengan API CloudKit. Penting untuk menangani kesalahan, menunjukkan kepada pengguna saat permintaan sedang berlangsung, memperbarui antarmuka pengguna, dan memberi tahu pengguna apa yang sedang terjadi.

Dalam artikel berikutnya dari seri ini, kami melihat lebih dekat hubungan dengan menambahkan kemampuan untuk mengisi daftar belanja dengan barang-barang. An empty shopping list isn't of much use and it certainly isn't fun. Tinggalkan pertanyaan apa pun yang Anda miliki di komentar di bawah atau hubungi saya di Twitter.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.