Jelajahi mengapa Zig mendapat perhatian untuk pekerjaan sistem tingkat rendah: desain bahasa sederhana, tooling praktis, interoperabilitas C yang bagus, dan kompilasi silang yang lebih mudah.

Pemrograman sistem tingkat rendah adalah pekerjaan di mana kode Anda dekat dengan mesin: Anda mengelola memori sendiri, memperhatikan bagaimana byte disusun, dan sering berinteraksi langsung dengan sistem operasi, perangkat keras, atau library C. Contoh tipikal termasuk firmware embedded, driver perangkat, engine game, alat baris perintah dengan kebutuhan kinerja ketat, dan pustaka dasar yang menjadi fondasi perangkat lunak lain.
"Lebih sederhana" bukan berarti "kurang kuat" atau "hanya untuk pemula." Ini berarti lebih sedikit aturan tersembunyi dan lebih sedikit bagian bergerak antara apa yang Anda tulis dan apa yang program lakukan.
Dengan Zig, istilah "alternatif yang lebih sederhana" biasanya menunjuk pada tiga hal:
Proyek sistem cenderung mengumpulkan "kompleksitas tak disengaja": build menjadi rapuh, perbedaan platform bertambah, dan debugging berubah menjadi arkeologi. Toolchain yang lebih sederhana dan bahasa yang lebih dapat diprediksi dapat mengurangi biaya pemeliharaan perangkat lunak selama bertahun-tahun.
Zig cocok untuk utilitas greenfield, pustaka sensitif-kinerja, dan proyek yang membutuhkan interoperabilitas C yang bersih atau kompilasi silang yang andal.
Ini tidak selalu pilihan terbaik ketika Anda butuh ekosistem library tingkat tinggi yang matang, riwayat rilis stabil yang panjang, atau ketika tim Anda sudah sangat berinvestasi di tooling dan pola Rust/C++. Daya tarik Zig adalah kejelasan dan kontrol—terutama ketika Anda menginginkannya tanpa banyak seremoni.
Zig adalah bahasa pemrograman sistem yang relatif muda, dibuat oleh Andrew Kelley pada pertengahan 2010-an, dengan tujuan praktis: membuat pemrograman tingkat rendah terasa lebih sederhana dan langsung tanpa mengorbankan kinerja. Ia mengambil nuansa "mirip C" (aliran kontrol jelas, akses langsung ke memori, tata letak data yang dapat diprediksi), namun berusaha menghilangkan banyak kompleksitas tak disengaja yang tumbuh di sekitar C dan C++.
Desain Zig berpusat pada eksplisititas dan prediktabilitas. Alih-alih menyembunyikan biaya di balik abstraksi, Zig mendorong kode di mana Anda biasanya bisa tahu apa yang terjadi hanya dengan membacanya:
Ini tidak berarti Zig "hanya untuk level rendah." Maksudnya Zig mencoba membuat pekerjaan tingkat rendah menjadi kurang rapuh: niat yang lebih jelas, lebih sedikit konversi implisit, dan fokus pada perilaku yang tetap konsisten di seluruh platform.
Salah satu tujuan kunci adalah mengurangi penyebaran toolchain. Zig memandang compiler lebih dari sekadar compiler: ia juga menyediakan sistem build terintegrasi dan dukungan testing, serta dapat mengambil dependensi sebagai bagian dari alur kerja. Maksudnya agar Anda bisa meng-clone sebuah proyek dan membangunnya dengan lebih sedikit prasyarat eksternal dan scripting khusus.
Zig juga dibangun dengan kepedulian pada portabilitas, yang berpadu alami dengan pendekatan satu-alat: perintah yang sama dirancang untuk membantu Anda membangun, menguji, dan menargetkan lingkungan berbeda dengan lebih sedikit seremoni.
Klaim Zig sebagai bahasa pemrograman sistem bukanlah "keamanan ajaib" atau "abstraksi yang jitu." Ini soal kejelasan. Bahasa berusaha menjaga jumlah gagasan inti kecil, dan lebih memilih mengeja sesuatu secara eksplisit daripada bergantung pada perilaku implisit. Untuk tim yang mempertimbangkan alternatif C (atau alternatif C++ yang lebih tenang), itu sering berarti kode yang lebih mudah dibaca enam bulan kemudian—terutama saat debugging jalur sensitif-kinerja.
Di Zig, Anda cenderung lebih jarang tersentak oleh apa yang sebuah baris kode picu di belakang layar. Fitur yang sering menciptakan perilaku "tak terlihat" di bahasa lain—alokasi implisit, exception yang melompat across frame, atau aturan konversi rumit—dibatasi secara sengaja.
Itu bukan berarti Zig minimal sampai membuat tak nyaman. Artinya Anda biasanya bisa menjawab pertanyaan dasar dengan membaca kode:
Zig menghindari exception dan menggunakan model eksplisit yang mudah dikenali dalam kode. Secara garis besar, sebuah error union berarti "operasi ini mengembalikan nilai atau error."
Anda sering melihat try digunakan untuk mempropagasi error ke atas (seperti mengatakan "jika ini gagal, hentikan dan kembalikan error"), atau catch untuk menangani kegagalan secara lokal. Manfaat utamanya adalah jalur kegagalan terlihat, dan aliran kontrol tetap dapat diprediksi—berguna untuk pekerjaan sensitif-kinerja dan bagi siapa saja yang membandingkan Zig dengan pendekatan Rust yang lebih penuh aturan.
Zig menargetkan seperangkat fitur yang ketat dengan aturan yang konsisten. Ketika ada lebih sedikit "pengecualian terhadap aturan," Anda menghabiskan lebih sedikit waktu menghafal kasus pinggir dan lebih banyak waktu fokus pada masalah pemrograman sistem yang sebenarnya: ketepatan, kecepatan, dan niat yang jelas.
Zig membuat pertukaran yang jelas: Anda mendapatkan kinerja yang dapat diprediksi dan model mental yang lugas, tetapi Anda bertanggung jawab atas memori. Tidak ada garbage collector tersembunyi yang menghentikan program Anda, dan tidak ada pelacakan lifetime otomatis yang diam-diam merombak desain Anda. Jika Anda mengalokasi memori, Anda juga menentukan siapa yang membebaskannya, kapan, dan dalam kondisi apa.
Di Zig, "manual" tidak berarti "berantakan." Bahasa mendorong pilihan yang eksplisit dan terbaca. Fungsi sering menerima allocator sebagai argumen, sehingga jelas apakah sebuah kode dapat melakukan alokasi, dan seberapa mahalnya. Visibilitas itu adalah intinya: Anda dapat menalar tentang biaya pada panggilan, bukan setelah kejutan profiling.
Daripada memperlakukan "heap" sebagai default, Zig mendorong Anda memilih strategi alokasi yang sesuai dengan pekerjaan:
Karena allocator adalah parameter kelas-satu, mengganti strategi biasanya sebuah refaktor, bukan penulisan ulang. Anda bisa mencoba dengan allocator sederhana, lalu beralih ke arena atau buffer tetap setelah memahami beban kerja sebenarnya.
Bahasa dengan GC mengoptimalkan kenyamanan pengembang: memori direklamasi otomatis, tetapi latensi dan puncak penggunaan memori bisa lebih sulit diprediksi.
Rust mengoptimalkan keamanan pada waktu kompilasi: ownership dan borrowing mencegah banyak bug, tetapi dapat menambah beban konseptual.
Zig duduk di tengah pragmatis: lebih sedikit aturan, lebih sedikit perilaku tersembunyi, dan penekanan pada membuat keputusan alokasi eksplisit—sehingga kinerja dan penggunaan memori lebih mudah diperkirakan.
Salah satu alasan Zig terasa "lebih sederhana" dalam pekerjaan sehari-hari adalah bahasa ini mengirimkan satu alat yang mencakup alur kerja paling umum: membangun, menguji, dan menargetkan platform lain. Anda menghabiskan lebih sedikit waktu memilih (dan merangkai) alat build, test runner, dan cross-compiler—dan lebih banyak waktu menulis kode.
Kebanyakan proyek dimulai dengan file build.zig yang menjelaskan apa yang ingin Anda hasilkan (executable, library, tes) dan bagaimana mengkonfigurasinya. Anda lalu mengendalikan semuanya lewat zig build, yang menyediakan langkah bernama.
Perintah tipikal terlihat seperti:
zig build
zig build run
zig build test
Itu adalah loop inti: definisikan langkah sekali, lalu jalankan secara konsisten di mesin mana pun dengan Zig terpasang. Untuk utilitas kecil, Anda juga bisa mengompilasi langsung tanpa skrip build:
zig build-exe src/main.zig
zig test src/main.zig
Kompilasi silang di Zig tidak diperlakukan sebagai "setup proyek terpisah." Anda bisa melewatkan target dan (opsional) mode optimisasi, dan Zig akan melakukan hal yang benar menggunakan tooling bawaannya.
zig build -Dtarget=x86_64-windows-gnu
zig build -Dtarget=aarch64-linux-musl -Doptimize=ReleaseSmall
Ini penting untuk tim yang mengirimkan alat baris perintah, komponen embedded, atau layanan yang dideploy di distro Linux berbeda—karena menghasilkan build Windows atau build yang terlink musl bisa sama rutinnya dengan build dev lokal Anda.
Kisah dependensi Zig terkait pada sistem build daripada dilapis di atasnya. Dependensi dapat dideklarasikan di sebuah manifest proyek (umumnya build.zig.zon) dengan versi dan hash konten. Secara garis besar, itu berarti dua orang yang membangun revisi yang sama dapat mengambil input yang sama dan mendapatkan hasil yang konsisten, dengan Zig melakukan caching artefak untuk menghindari pekerjaan berulang.
Ini bukan "reproducibility ajaib," tetapi mendorong proyek ke arah build yang dapat diulang secara default—tanpa meminta Anda mengadopsi manajer dependensi terpisah dulu.
comptime Zig adalah ide sederhana dengan hasil besar: Anda bisa menjalankan beberapa kode saat kompilasi untuk menghasilkan kode lain, menspesialisasi fungsi, atau memvalidasi asumsi sebelum program dikirim. Alih-alih substitusi teks (seperti preprocessor C/C++), Anda menggunakan sintaks Zig normal dan tipe Zig normal—hanya dijalankan lebih awal.
Menghasilkan kode: membangun tipe, fungsi, atau tabel lookup berdasarkan input yang diketahui saat kompilasi (mis. fitur CPU, versi protokol, atau daftar field).
Memvalidasi konfigurasi: menangkap opsi yang tidak valid lebih awal—sebelum binary diproduksi—sehingga "terkompilasi" benar-benar berarti sesuatu.
Makro C/C++ kuat, tetapi bekerja pada teks mentah. Itu membuatnya sulit di-debug dan mudah disalahgunakan (presedensi tak terduga, tanda kurung hilang, pesan error aneh). Comptime Zig menghindari itu dengan tetap berada di dalam bahasa: aturan scope, tipe, dan tooling masih berlaku.
Berikut beberapa pola umum:
const std = @import("std");
pub fn buildConfig(comptime port: u16, comptime enable_tls: bool) type {
if (port == 0) @compileError("port must be non-zero");
if (enable_tls and port == 80) @compileError("TLS usually shouldn't run on port 80");
return struct {
pub const Port = port;
pub const TlsEnabled = enable_tls;
};
}
Ini memungkinkan Anda membuat "tipe" konfigurasi yang membawa konstanta yang tervalidasi. Jika seseorang melewatkan nilai buruk, compiler berhenti dengan pesan jelas—tanpa pemeriksaan runtime, tanpa logika makro tersembunyi, dan tanpa kejutan di kemudian hari.
Klaim Zig bukanlah "tulis ulang semua." Bagian besar daya tariknya adalah Anda dapat mempertahankan kode C yang sudah Anda percaya dan bergerak secara bertahap—modul demi modul, file demi file—tanpa memaksa migrasi besar-besaran.
Zig dapat memanggil fungsi C dengan sedikit upacara. Jika Anda sudah bergantung pada library seperti zlib, OpenSSL, SQLite, atau SDK platform, Anda bisa terus menggunakannya sambil menulis logika baru di Zig. Itu menjaga risiko rendah: dependensi C yang terbukti tetap ada, sementara Zig menangani bagian baru.
Sama pentingnya, Zig juga mengekspor fungsi yang bisa dipanggil C. Itu membuat praktis untuk memperkenalkan Zig ke proyek C/C++ yang ada sebagai pustaka kecil terlebih dahulu, bukan rewrite penuh.
Alih-alih memelihara binding buatan tangan, Zig dapat mengonsumsi header C saat build menggunakan @cImport. Sistem build dapat menetapkan path include, macro fitur, dan detail target sehingga API yang diimpor cocok dengan cara kode C Anda dikompilasi.
const c = @cImport({
@cInclude("stdio.h");
});
Pendekatan ini menjaga "sumber kebenaran" di header C asli, mengurangi drift saat dependensi diperbarui.
Sebagian besar pekerjaan sistem menyentuh API sistem operasi dan basis kode lama. Interoperabilitas C Zig mengubah realitas itu menjadi keuntungan: Anda bisa memodernkan tooling dan pengalaman pengembang sambil tetap berbicara dalam bahasa asli pustaka sistem. Untuk tim, itu sering berarti adopsi lebih cepat, diff review lebih kecil, dan jalur yang lebih jelas dari "eksperimen" ke "produksi."
Zig dibangun pada janji sederhana: apa yang Anda tulis harus memetakan dekat dengan apa yang mesin lakukan. Itu tidak berarti "selalu tercepat," tetapi berarti lebih sedikit penalti tersembunyi dan lebih sedikit kejutan ketika Anda mengejar latensi, ukuran, atau waktu startup.
Zig menghindari keharusan runtime (seperti GC atau layanan latar wajib) untuk program biasa. Anda bisa mengirim binary kecil, mengontrol inisialisasi, dan menjaga biaya eksekusi tetap di bawah kendali Anda.
Model mental yang berguna: jika sesuatu menghabiskan waktu atau memori, Anda harus bisa menunjuk ke baris kode yang memilih biaya itu.
Zig berusaha membuat sumber perilaku yang tidak terduga menjadi eksplisit:
Pendekatan ini membantu ketika Anda perlu memperkirakan perilaku kasus terburuk, bukan sekadar rata-rata.
Saat mengoptimalkan kode sistem, perbaikan tercepat seringkali yang bisa Anda konfirmasi dengan cepat. Penekanan Zig pada aliran kontrol yang lugas dan perilaku eksplisit cenderung menghasilkan stack trace yang lebih mudah diikuti, dibandingkan basis kode yang berat trik makro atau lapisan generated yang buram.
Dalam praktiknya, itu berarti lebih sedikit waktu "menginterpretasi" program dan lebih banyak waktu mengukur dan memperbaiki bagian yang benar-benar penting.
Zig tidak mencoba "mengalahkan" setiap bahasa sistem sekaligus. Ia meraih ruang tengah praktis: kontrol dekat-mesin seperti C, pengalaman yang lebih bersih dibandingkan setup build C/C++ warisan, dan lebih sedikit konsep curam dibanding Rust—dengan biaya tidak memiliki jaminan keamanan setingkat Rust.
Jika Anda sudah menulis C untuk binary kecil dan dapat diandalkan, Zig sering dapat menggantikan tanpa mengubah bentuk proyek.
Gaya "bayar sesuai penggunaan" Zig dan pilihan memori eksplisit membuatnya jalur peningkatan yang masuk akal untuk banyak basis kode C—terutama saat Anda lelah dengan skrip build rapuh dan keanehan platform.
Zig bisa jadi opsi kuat untuk modul fokus-kinerja di mana C++ sering dipilih terutama karena kecepatan dan kontrol:
Dibandingkan C++ modern, Zig cenderung terasa lebih seragam: lebih sedikit aturan tersembunyi, lebih sedikit "sihir," dan toolchain standar yang menangani build dan kompilasi silang di satu tempat.
Rust sulit ditandingi ketika tujuan utama adalah mencegah kelas bug memori di waktu kompilasi. Jika Anda memerlukan jaminan kuat yang ditegakkan tentang aliasing, lifetime, dan race kondisi—terutama dalam tim besar atau kode sangat konkurent—model Rust adalah keuntungan besar.
Zig bisa lebih aman daripada C melalui disiplin dan pengujian, tetapi umumnya lebih mengandalkan pengembang membuat pilihan yang benar, bukan compiler yang membuktikannya.
Adopsi Zig lebih didorong oleh tim yang menemukannya praktis dalam beberapa skenario berulang. Ia sangat menarik ketika Anda menginginkan kontrol tingkat rendah tetapi tidak ingin membawa permukaan bahasa dan tooling yang besar ke dalam proyek.
Zig nyaman di lingkungan "freestanding"—kode yang tidak mengasumsikan sistem operasi penuh atau runtime standar. Itu membuatnya kandidat alami untuk firmware embedded, utilitas waktu-boot, kerja OS hobi, dan binary kecil di mana Anda peduli apa yang di-link dan apa yang tidak.
Anda tetap perlu tahu target dan batas perangkat keras, tetapi model kompilasi Zig yang lugas dan eksplisit cocok dengan sistem yang sumber dayanya terbatas.
Banyak penggunaan dunia nyata muncul di:
Proyek-proyek ini sering mendapat manfaat dari fokus Zig pada kontrol jelas atas memori dan eksekusi tanpa memaksa runtime atau kerangka kerja tertentu.
Zig adalah pilihan baik ketika Anda menginginkan binary ringkas, build lintas-target, interoperabilitas C, dan basis kode yang tetap terbaca dengan lebih sedikit "mode" bahasa. Ia kurang cocok jika proyek Anda bergantung pada paket ekosistem Zig yang besar, atau jika Anda membutuhkan konvensi tooling yang matang.
Pendekatan praktis adalah membuat pilot Zig pada komponen terbatas (pustaka, alat CLI, atau modul kritis-kinerja) dan mengukur kesederhanaan build, pengalaman debugging, dan usaha integrasi sebelum berkomitmen lebih luas.
Pitch Zig adalah "sederhana dan eksplisit," tetapi itu tidak berarti cocok untuk setiap tim atau basis kode. Sebelum mengadopsinya untuk pekerjaan sistem serius, baik untuk jelas tentang apa yang Anda dapatkan—dan apa yang Anda korbankan.
Zig sengaja tidak memaksa satu model keselamatan memori. Anda biasanya mengelola lifetime, alokasi, dan jalur error secara eksplisit, dan Anda dapat menulis kode yang berbahaya jika memilih demikian.
Itu bisa menjadi manfaat untuk tim yang menghargai kontrol dan prediktabilitas, tetapi menggeser tanggung jawab ke disiplin engineering: standar review kode, praktik pengujian, dan kepemilikan yang jelas pada pola alokasi memori. Build debug dan cek keselamatan dapat menangkap banyak masalah, tetapi bukan pengganti desain bahasa yang berorientasi keselamatan.
Dibandingkan ekosistem mapan, dunia paket dan pustaka Zig masih matang. Anda mungkin menemukan lebih sedikit pustaka "batteries included", celah di domain khusus, dan perubahan yang lebih sering pada paket komunitas.
Zig sendiri juga mengalami periode di mana bahasa dan tooling berubah sehingga memerlukan upgrade dan penulisan ulang kecil. Itu bisa dikelola, tetapi penting jika Anda butuh stabilitas jangka panjang, kepatuhan ketat, atau pohon dependensi besar.
Tooling bawaan Zig dapat menyederhanakan build, tetapi Anda masih perlu mengintegrasikannya ke alur kerja nyata: caching CI, build dapat direproduksi, packaging rilis, dan testing multi-platform.
Dukungan editor makin baik, tetapi pengalaman bisa bervariasi tergantung IDE dan setup language server Anda. Debugging umumnya solid via debugger standar, namun quirks platform-spesifik dapat muncul—terutama saat kompilasi silang atau menargetkan lingkungan kurang umum.
Jika Anda mengevaluasi Zig, jalankan pilot pada komponen terkontrol dulu, dan pastikan target, pustaka, dan tooling yang Anda butuhkan semuanya bisa bekerja end-to-end.
Zig paling mudah dinilai dengan mencobanya pada potongan nyata dari basis kode Anda—cukup kecil untuk aman, tetapi cukup bermakna untuk mengekspos gesekan sehari-hari.
Pilih komponen yang punya input/output jelas dan permukaan terbatas:
Tujuannya bukan membuktikan Zig bisa melakukan segalanya; tetapi melihat apakah ia meningkatkan kejelasan, debugging, dan pemeliharaan untuk satu pekerjaan konkret.
Bahkan sebelum menulis ulang kode, Anda bisa mengevaluasi Zig dengan mengadopsi tool-nya di area yang memberi leverage langsung:
Ini memungkinkan tim menilai pengalaman pengembang (kecepatan build, pesan error, caching, dukungan target) tanpa berkomitmen pada rewrite penuh.
Pola umum adalah menjaga Zig fokus pada inti kinerja (utilitas CLI, pustaka, kode protokol), sementara bagian produk yang lebih tinggi—dashboard admin, tooling internal, dan glue deployment—dibangun lebih cepat dengan platform lain. Jika Anda ingin mengirim bagian seputar itu cepat, platform seperti Koder.ai bisa membantu: Anda dapat membangun web app (React), backend (Go + PostgreSQL), atau mobile app (Flutter) dari alur kerja berbasis chat, lalu mengintegrasikan komponen Zig Anda melalui lapisan API tipis. Pembagian kerja itu menjaga Zig tetap di area yang unggul (prediktabilitas perilaku tingkat rendah) sambil mengurangi waktu untuk plumbing non-inti.
Fokus pada kriteria praktis:
Jika modul pilot berhasil di-deploy dan tim ingin terus menggunakan alur yang sama, itu sinyal kuat bahwa Zig cocok untuk batas berikutnya.
Dalam konteks ini, “lebih sederhana” berarti lebih sedikit aturan tersembunyi antara apa yang Anda tulis dan apa yang dilakukan program. Zig cenderung ke arah:
Ini soal prediktabilitas dan pemeliharaan, bukan “kurang kapabel.”
Zig cenderung cocok ketika Anda peduli pada kontrol ketat, kinerja yang dapat diprediksi, dan pemeliharaan jangka panjang:
Zig menggunakan manajemen memori manual, tetapi berusaha membuatnya disiplin dan terlihat. Pola umum adalah meneruskan sebuah allocator ke kode yang mungkin melakukan alokasi, sehingga pemanggil dapat melihat biaya dan memilih strategi.
Kesimpulan praktis: jika suatu fungsi menerima allocator, anggaplah ia mungkin mengalokasi dan rencanakan kepemilikan/pembebasan memori sesuai.
Zig umum menggunakan pola “parameter allocator” sehingga Anda dapat memilih strategi per beban kerja:
Ini memudahkan mengganti strategi alokasi tanpa menulis ulang seluruh modul.
Zig memperlakukan error sebagai nilai melalui error union (operasi mengembalikan nilai atau error). Dua operator umum:
try: mempropagasi error ke atas jika terjadicatch: menangani error secara lokal (opsional dengan fallback)Karena kegagalan adalah bagian dari tipe dan sintaks, Anda biasanya bisa melihat semua titik kegagalan hanya dengan membaca kode.
Zig hadir dengan workflow terintegrasi yang digerakkan oleh zig:
zig build untuk langkah build yang didefinisikan di build.zigzig build test (atau zig test file.zig) untuk tesKompilasi silang dirancang agar menjadi hal yang rutin: Anda hanya memberi target, dan Zig menggunakan tooling bawaan untuk membangun untuk platform itu.
Contoh pola:
zig build -Dtarget=x86_64-windows-gnuzig build -Dtarget=aarch64-linux-muslIni berguna ketika Anda perlu build yang dapat diulang untuk berbagai kombinasi OS/CPU/libc tanpa memelihara toolchain terpisah.
comptime membiarkan Anda menjalankan sebagian kode Zig saat waktu kompilasi untuk menghasilkan kode lain, menspesialisasi fungsi, atau memvalidasi asumsi sebelum binary dibuat.
Penggunaan umum:
@compileError (gagal cepat saat kompilasi)Ini alternatif yang lebih aman dibandingkan pola makro karena tetap menggunakan sintaks dan tipe Zig normal, bukan substitusi teks.
Zig dapat berinteroperasi dengan C dua arah:
@cImport sehingga binding berasal dari header asliIni membuat adopsi bertahap menjadi praktis: Anda dapat mengganti atau membungkus satu modul sekaligus, bukan menulis ulang seluruh basis kode.
Zig mungkin kurang cocok ketika Anda membutuhkan:
Pendekatan praktis: jalankan pilot pada komponen yang dibatasi terlebih dahulu, lalu putuskan berdasarkan kesederhanaan build, pengalaman debugging, dan dukungan target.
zig fmt untuk formatManfaat praktisnya: lebih sedikit alat eksternal untuk diinstal dan lebih sedikit skrip ad-hoc yang harus disinkronkan di mesin dan CI.