65
BAB IV
IMPLEMENTASI DAN PENGUJIAN
Pada bab ini akan dibahas mengenai implementasi atau cara penggunaan
aplikasi dan juga pengujian sistem dengan metode
Black-Box
.
4.1
IMPLEMENTASI APLIKASI
Pada implementasi ini akan dibahas mengenai implementasi source kode
untuk pembuatan antarmuka dari aplikasi ini beserta tampilan hasil antarmuka
tersebut. Aplikasi ini mempunyai menu yang terdiri dari menu
Logout
, menu
Template
, menu
Capture Data
dan menu
Data
. Gambar 4.1 menunjukkan lebih
jelas peletakan dari menu-menu yang disebutkan diatas
Gambar 4.1
Tampilan
MainForm
Menu
4.1.1
Logout
1.
Adalah proses untuk mengakhiri sesi dari user dalam aplikasi.
2.
Apabila di klik maka akan muncul
Login Form
, di
form
ini user
memasukkan
usercode
dan
password
untuk login ke aplikasi.
Gambar 4.2
Tampilan Login
Form
Berikut potongan
source code
ketika menu
Logout
ditekan
foreach (Form f in base.MdiChildren) { f.Close(); f.Dispose(); } this.isActiveLogin = false; ribbon.Pages.Clear(); this.Close(); ...
4.1.2
Template
Proses ini digunakan untuk membuat template dan melakukan
mapping
koordinat dari gambar ke kolom tabel application. Menu
Template
hanya bisa
diakses oleh Administrator.
4.1.2.1
Template Manager
Isi nama
Template
dan
Template Description
.
Gambar 4.3
Tampilan
Template Manager Form
1.
Potongan
source code
dari
Template Manager Form
…
private void TemplateView_Load(object sender, EventArgs e)
{
this.BindGrid(); }
…
private void BindGrid() {
string sql = "SELECT * FROM dbo.Template"; try
DataSet ds = CDA.GetDataset(sql, "Template"); this.templateViewDS1.Template.Clear();
this.templateViewDS1.Merge(ds); }
catch (Exception ex) {
Utils.Misc.ShowInfo("Failed to load template data! \nError at : "+ex.Message);
} }
2.
Pilih gambar yang akan dijadikan template, dengan mengklik tombol
di kolom
image
, sehingga muncul jendela baru.
Gambar 4.4
Jendela
select template image
3.
Potongan
source code
proses
select template image
private void repositoryItemButtonEdit1_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e) { string templateName = this.gridView1.GetRowCellValue(this.gridView1.FocusedRowH andle, colTemplateName).ToString(); if(templateName == "") return; if (openFileDialog1.ShowDialog() == DialogResult.OK) {
string path = openFileDialog1.FileName; string filename =
path.Substring((path.LastIndexOf("\\")) + 1); string mimeType =
FileInfo fi = new FileInfo(path);
fi.CopyTo(this.AppInfo.TemplateImagePath + templateName + "." +mimeType);
this.gridView1.SetRowCellValue(this.gridView1.FocusedRowH andle, colTemplateImageName, templateName + "." +
mimeType);
this.gridView1.SetRowCellValue(this.gridView1.FocusedRowH andle, colImagePath, this.AppInfo.TemplateImagePath + templateName + "." + mimeType);
} }
4.
File
gambar akan disalin ke
folder TemplateImage
.
5.
Klik tombol
Save.
6.
Berikut potongan
Source Code
, dari
Save Data.
private void SaveData() {
dlg = new WaitDialogForm("Loading please wait....", "Saving Data");
DataSet ds = (DataSet)gridControl1.DataSource; string sql = "SELECT * FROM dbo.Template";
try { gridControl1.BeginUpdate(); if (ds.HasChanges()) { CDA.ExecuteDatasetUpdate(ds.GetChanges(), sql, "Template"); } gridControl1.EndUpdate(); }
catch (Exception ex) { Utils.Misc.ShowError("error : " + ex.Message); dlg.Close(); } dlg.Close(); this.BindGrid(); }
4.1.2.2
Template Mapping
1.
Adalah proses
mapping
koordinat gambar dengan kolom
application
.
2.
Pilih
Template
yang akan di
mapping
.
Gambar 4.5
Select template name
3.
Klik tombol
Mapping
, maka
user
akan dihadapkan dengan
form Template
Gambar 4.6
Template Mapping Form
4.
Potongan
source code Template Mapping Form
private void TemplateForm_Load(object sender, EventArgs e) { this.InitApp(); this.BindLue(); this.BindGrid(); }
5.
Klik tombol + di panel
Application Table
, kemudian pilih kolom mana
Gambar 4.7
Pilih kolom
Application table
yang dimapping
6.
Seleksi area di gambar untuk menentukan koordinat dari gambar yang
akan dimapping ke kolom yang telah dipilih.
7.
Potongan
source code
dari proses seleksi area yang dimapping ke kolom
private void pictureEdit1_MouseDown(object sender, MouseEventArgs e)
{
if (this.isLoadSelection) return;
rectangles.Clear();
currentPos = startPos = e.Location; drawing = true;
}
private void pictureEdit1_MouseMove(object sender, MouseEventArgs e)
{
// This makes sure that the left mouse button is pressed.
if (e.Button == MouseButtons.Left) {
// Draws the rectangle as the mouse moves this.isLoadSelection = false; currentPos = e.Location; if (drawing) pictureEdit1.Invalidate(); } }
private void pictureEdit1_Paint(object sender, PaintEventArgs e) { if (this.isLoadSelection) { this.LoadSelection(e.Graphics); } else { this.barButtonItem1.Caption = "Load Selection"; if (rectangles.Count > 0) e.Graphics.DrawRectangles(Pens.Black, rectangles.ToArray()); if (drawing) e.Graphics.DrawRectangle(Pens.Red, getRectangle()); } } …
private void pictureEdit1_MouseMove(object sender, MouseEventArgs e)
{
// This makes sure that the left mouse button is pressed.
if (e.Button == MouseButtons.Left) {
// Draws the rectangle as the mouse moves this.isLoadSelection = false;
currentPos = e.Location;
if (drawing) pictureEdit1.Invalidate();
} }
8.
Lakukan langkah 5-6 sampai semua kolom sudah termapping.
Gambar 4.9
Semua Kolom Sudah Termapping
9.
Klik tombol
Save
, maka proses mapping selesai.
10.
Berikut potongan
source code
proses
save data
.
…
this.SaveData();
this.GenerateApplicationStoredProcedure(this.TemplateID);
…
private void SaveData() {
dlg = new WaitDialogForm("Loading please wait....", "Saving Data");
ADESAppSystem sys = new ADESAppSystem(); sys.AppInfo = this.AppInfo;
try {
sys.SaveTemplateColumn(this.templateFormDS1, this.TemplateID);
}
catch (Exception ex) { Utils.Misc.ShowInfo("Failed to SaveData! \nError : " + ex.Message); dlg.Close(); } dlg.Close(); this.BindGrid(); } …
public void GenerateApplicationStoredProcedure(int templateID)
{
string result = "";
StringBuilder sb = new StringBuilder(""); StringBuilder sbc = new StringBuilder(""); if
(this.templateFormDS1.TemplateColumn.Rows.Count > 0) {
sbc.AppendLine(@"IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[sp_InsertDataApplication_" +
templateID.ToString() + "]') AND type in (N'P', N'PC'))"); sbc.AppendLine(@" DROP PROCEDURE
[dbo].[sp_InsertDataApplication_" + templateID.ToString() + "] "); sb.AppendLine(@"CREATE PROCEDURE sp_InsertDataApplication_"+templateID.ToString()); //add parameter string dlm = "";
foreach (DataRow row in templateFormDS1.TemplateColumn.Rows) { sb.AppendLine(dlm + "@"+row["ColumnName"].ToString() + " VARCHAR(255)"); dlm = ","; }
sb.AppendLine(dlm + "@TemplateID INT"); dlm = "";
sb.AppendLine(@"AS"); sb.AppendLine("");
sb.AppendLine(@"INSERT INTO Application "); sb.AppendLine(@"(");
foreach (DataRow row in templateFormDS1.TemplateColumn.Rows) { sb.AppendLine(dlm + row["ColumnName"].ToString()); dlm = ","; } sb.AppendLine(dlm + "TemplateID"); sb.AppendLine(@")"); dlm = "";
sb.AppendLine("VALUES"); sb.AppendLine("("); foreach (DataRow row in templateFormDS1.TemplateColumn.Rows) { sb.AppendLine(dlm + "@" + row["ColumnName"].ToString()); dlm = ","; } sb.AppendLine(dlm + "@TemplateID"); sb.AppendLine(")");
sb.AppendLine(@"SELECT @@IDENTITY FROM Application"); result = sb.ToString(); } try { CDA.ExecuteNonQueryWithTransaction(sbc.ToString()); CDA.ExecuteNonQueryWithTransaction(result); SqlCommand cmd = new SqlCommand("UPDATE Template SET StoredProcedure=@sp WHERE TemplateID = @TemplateID"); cmd.Parameters.AddWithValue("@sp", "sp_InsertDataApplication_" + templateID.ToString()); cmd.Parameters.AddWithValue("@TemplateID", templateID); CDA.ExecuteNonQueryWithTransaction(cmd); }
catch (Exception ex) {
Utils.Misc.ShowInfo("Failed to generate stored procedure. \nError : "+ ex.Message);
}
this.memoSqlScript.Text = result; }
11.
Klik
Load Mapping
untuk melihat hasil dari proses mapping
Gambar 4.10
Mapping Result
12.
Potongan
source code Load Mapping
private void LoadSelection(Graphics g) {
this.rectangles.Clear();
SqlCommand cmd = new SqlCommand("SELECT * FROM dbo.TemplateColumn WHERE TemplateID = @TemplateID"); cmd.Parameters.AddWithValue("@TemplateID", this.TemplateID);
DataTable dt = CDA.GetDataTable(cmd);
int x1 = 0, x2 = 0, y1 = 0, y2 = 0; Rectangle rect = new Rectangle();
Pen pen = null;
foreach (DataRow row in dt.Rows) {
x1 = Convert.ToInt32(row["StartPosX"]); x2 = Convert.ToInt32(row["CurrentPosX"]); y1 = Convert.ToInt32(row["StartPosY"]); y2 = Convert.ToInt32(row["CurrentPosY"]); pen = new Pen(Color.Blue, 2);
rect = new Rectangle( Math.Min(x1, x2),
Math.Min(y1, y2), Math.Abs(x1 - x2), Math.Abs(y1 - y2)); g.DrawRectangle(pen, rect); } }
4.1.3
Capture Data
1.
Adalah proses memindahkan teks yang ada di dokumen langsung ke
database secara otomatis berdasarkan
mapping
yang telah dibuat.
2.
Proses ini dilakukan oleh operator.
3.
Klik tombol
Capture Data
di
MainForm
, maka
user
akan dihadapkan
dengan
form Capture Data
.
Gambar 4.11
Capture Data Form
private void CaptureDataView_Load(object sender, EventArgs e) { //init dtImageList.Columns.Add("image", typeof(string)); dtImageList.Columns.Add("path", typeof(string)); this.BindLue(); } …
private void BindLue() {
string sql = "SELECT TemplateID, TemplateName, TemplateDescription FROM dbo.Template";
DataTable dt = CDA.GetDataTable(sql); this.lueTemplate.Properties.DataSource = dt; this.lueTemplate.Properties.ValueMember = "TemplateID"; this.lueTemplate.Properties.DisplayMember = "TemplateName"; }
5.
Klik tombol
Open Doc
untuk menentukan di
folder
mana lokasi
dokumen yang akan di pindahkan datanya. Kemudian klik OK.
6.
Potongan
source code
proses
Open Doc
private void OpenFolder() { this.pictureEdit1.Image = null; if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) { this.openedDirPath = folderBrowserDialog1.SelectedPath; this.BindImageList(); } }
7.
Pilih dokumen yang akan di
capture
, dengan menyeleksi salah satu file
di panel
image list
.
Gambar 4.13
Memilih Dokumen yang akan Diproses
8.
Potongan
source code
pada waktu memilih dokumen
private void SetImageToEditor() {
if (this.dtImageList.Rows.Count <= 0) return; if
(this.gridView1.GetDataRow(this.gridView1.FocusedRowHa ndle) == null) return;
m_image = new Bitmap(this.SelectedImageFilePath); m_image.SetResolution(96, 96); m_words = null; pictureEdit1.Image = m_image; panelEditor.AutoScrollMinSize = m_image.Size; }
9.
Pilih
template
yang akan digunakan, dengan menekan
combobox select
template
di panel
result
.
Gambar 4.14
Memilih
Template
yang Akan Dipakai
10.
Potongan
source code
memilih
template
if (this.lueTemplate.EditValue != DBNull.Value) this.BindGridResult();
…
{
int templateID =
Convert.ToInt32(this.lueTemplate.EditValue);
string sql = "SELECT * FROM dbo.TemplateColumn WHERE TemplateID = @TemplateID";
SqlCommand cmd = new SqlCommand(sql);
cmd.Parameters.AddWithValue("@TemplateID", templateID); try
{
this.captureDataResultDS1.TemplateColumn.Clear(); DataSet ds = CDA.GetDataset(cmd, "TemplateColumn"); this.captureDataResultDS1.Merge(ds);
}
catch (Exception ex) {
Utils.Misc.ShowInfo("Failed to load capture data! \nError : " + ex.Message);
} }
11.
Klik tombol
Load Template Mapping
, maka akan muncul kotak-kotak
merah yang merupakan area koordinat yang telah di
mapping
.
Gambar 4.15
Load template mapping
12.
Potongan
source code
pada saat Load Template Mapping
private void LoadSelection(Graphics grapich) {
if (this.lueTemplate.EditValue == null) {
Utils.Misc.ShowInfo("Select Template Please !"); this.lueTemplate.Focus();
this.isSelectionLoaded = false; } else { if (this.isSelectionLoaded) { this.rectangles.Clear();
SqlCommand cmd = new SqlCommand("SELECT * FROM dbo.TemplateColumn WHERE TemplateID = @TemplateID");
cmd.Parameters.AddWithValue("@TemplateID", this.TemplateID);
DataTable dt = CDA.GetDataTable(cmd); int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
//grapImage = pictureEdit1.CreateGraphics(); Rectangle rect = new Rectangle();
Pen pen = null;
foreach (DataRow row in dt.Rows) {
x1 = Convert.ToInt32(row["StartPosX"]); x2 = Convert.ToInt32(row["CurrentPosX"]); y1 = Convert.ToInt32(row["StartPosY"]); y2 = Convert.ToInt32(row["CurrentPosY"]); pen = new Pen(Color.Red, 2);
rect = new Rectangle( Math.Min(x1, x2), Math.Min(y1, y2), Math.Abs(x1 - x2), Math.Abs(y1 - y2)); grapich.DrawRectangle(pen, rect); } } else { this.pictureEdit1.Invalidate(); } } }
13.
Klik tombol
Capture
, maka hasil dari capture data bisa dilihat di
grid
di panel
result
, apabila hasil capture kurang akurat maka
user
bisa
Gambar 4.16
Hasil
Capture Data
14.
Potongan
source code
pada waktu proses
capture data
private void tbtnCapture_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
try {
dlg = new WaitDialogForm("Please wait...", "Loading");
if (m_image != null && !string.IsNullOrEmpty(AppInfo.TessLang)) {
tessnet2.Tesseract ocr = new tessnet2.Tesseract();
ocr.Init(AppInfo.TessDataPath,
AppInfo.TessLang, false);
Rectangle rect;
this.gridViewResult.BeginUpdate(); foreach (DataRow row in
captureDataResultDS1.TemplateColumn.Rows) { int startPosX = Convert.ToInt32(row["StartPosX"]); int currentPosX = Convert.ToInt32(row["CurrentPosX"]); int startPosY = Convert.ToInt32(row["StartPosY"]);
int currentPosY = Convert.ToInt32(row["CurrentPosY"]);
rect = new Rectangle( Math.Min(startPosX, currentPosX), Math.Min(startPosY, currentPosY), Math.Abs(startPosX - currentPosX), Math.Abs(startPosY - currentPosY) );
m_words = ocr.DoOCR(m_image, rect);
row["Result"] = this.getResultText; } this.gridViewResult.EndUpdate(); } dlg.Close(); }
catch (Exception ex) { dlg.Close(); Utils.Misc.ShowInfo("Exception : " + ex.Message + "\n" + ex.StackTrace); } }
15.
Klik tombol
Save
, maka data – data yang telah dicapture akan di
insert
ke tabel
application
di
database
secara langsung.
16.
Berikut potongan
source code
dari proses save data.
private void SaveData() {
try {
if (Utils.Misc.ShowConfirmation("Are sure to save data ? ", "Save"))
{ int applicationID = 0; dlg = new WaitDialogForm("Loading"); if (this.captureDataResultDS1.TemplateColumn.Rows.Count > 0) { SqlCommand cmd = new SqlCommand(this.StoredProcedureName); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@TemplateID", this.TemplateID);
foreach (DataRow row in this.captureDataResultDS1.TemplateColumn.Rows) { cmd.Parameters.AddWithValue("@" + row["ColumnName"].ToString(), row["Result"]); } applicationID = Convert.ToInt32(CDA.ExecuteScalar(cmd)); }
#region copy image to ApplicationImage Folder string newPath = ""; if (this.SelectedImageFilePath != "") { string path = this.SelectedImageFilePath; string filename = path.Substring((path.LastIndexOf("\\")) + 1); string mimeType = filename.Substring((filename.LastIndexOf(".")) + 1);
FileInfo fi = new FileInfo(path); newPath =
this.AppInfo.ApplicationImagePath + "Application_" + applicationID.ToString() + "." + mimeType;
FileInfo fid = new FileInfo(newPath); if (fid.Exists) fid.Delete(); fid.Refresh(); fi.CopyTo(newPath); } #endregion
#region Update App ImagePath SqlCommand cmdu = new
SqlCommand("UPDATE Application Set ImagePath = @ImagePath WHERE ApplicationID = @ApplicationID");
cmdu.Parameters.AddWithValue(@"ImagePath", newPath); cmdu.Parameters.AddWithValue(@"ApplicationID", applicationID); CDA.ExecuteNonQueryWithTransaction(cmdu); #endregion dlg.Close(); } }
catch (Exception ex) {
dlg.Close();
Utils.Misc.ShowInfo("Failed to save data. \nError : "+ ex.Message);
} }
4.2
PENGUJIAN SISTEM
Dalam proses pengujian aplikasi ini, penulis menggunakan metode
black-box
. Metode ini bertujuan untuk menunjukkan fungsi aplikasi tentang cara
beroperasinya, apakah pemasukan data keluaran telah berjalan sebagaimana yang
diharapkan. Pengujian
black-box
ini berfokus pada persyaratan fungsional
aplikasi. Pengujian inimemungkinkan sistem analis dapat memperoleh kumpulan
kondisi input, yang akan mengerjakan seluruh keperluan fungsional dari aplikasi.
Adapun hasil dari pengujian tersebut adalah sebagai berikut:
Item Yang Diuji Hasil (Kondisi Normal) Hasil (Kondisi Tidak Normal) Hasil Yang Diperoleh Sukses Login User berhasil masuk ke aplikasi dan mempunyai hak akses sesuai role nya
User gagal masuk aplikasi atau user mempunyai akses yang tidak sesuai dengan role-nya
User berhasil masuk, Role
sesuai √
Logout
User keluar dari aplikasi dan muncul LoginForm
User tidak bisa keluar dari aplikasi atau LoginForm tidak muncul
User keluar dari aplikasi, LoginForm muncul √ Load Template Manager Form Form berhasil di ditampilkan beserta data-data yang pernah diinput sebelumnya Form tidak berhasil di tampilkan atau data yang pernah diinput tidak ikut ditampilkan
Form sukses ditampilkan beserta data – data yang pernah diinput √ Memilih template dokumen Muncul window untuk memilih file JPG di lokal komputer Window tidak muncul Window berhasil muncul dan membaca file JPG √
Save Template Data
Template berhasil di simpan, hasil langsung ditampilkan di datagrid Template gagal di simpan atau hasil tidak ditampilkan di datagrid Template berhasil disimpan, hasil ditampilkan di datagrid √
Edit Template Data Kolom di datagrid dalam keadaan
Kolom di datagrid dalam keadaan
Kolom di datagrid
aktif dan editable inaktif dan uneditable
aktif dan editable
Delete Template Data Data template berhasil di hapus dan datagrid otomatis di refresh Data template gagal dihapus atau datagrid tidak otomatis refresh Data template berhasil di hapus dan datagrid otomatis di refresh √ Load TemplateMapping Form Form TemplateMapping berhasil di load beserta data penunjangnya, file dokumen muncul di pictureEdit Form TemplateMapping gagal di load atau data penunjang tidak sesuai Form TemplateMapping berhasil di load dan data penunjang sesuai, file dokumen muncul di pictureEdit √ Load Mapping Koordinat Data mapping keluar dengan membentuk kotak – kotak di pictureEdit Data mapping tidak keluar , kotak di pictureEdit tidak muncul Data mapping keluar dengan membentuk kotak – kotak di pictureEdit √ Unload Mapping Koordinat Kotak – kotak di pictureEdit hilang Kotak – kotak di pictureEdit tidak hilang Kotak – kotak di pictureEdit hilang √ Refresh TemplateMapping Form Data penunjang templateMapping berhasil di load, file dokumen muncul di pictureEdit Data penunjang templateMapping gagal di load, file dokumen tidak muncul di pictureEdit Data penunjang templateMapping berhasil di load, file dokumen muncul di pictureEdit √ Save Template Mapping Data mapping berhasil di save ke table TemplateColumn Data mapping gagal di save ke table TemplateColumn Data mapping berhasil di save ke table TemplateColumn √ Load CaptureData Form Form Capture Data berhasil di tampilkan, combobox
template list terisi dengan data template, datagrid imagelist blank, pictureEdit blank, datagrid result blank Form Capture Data gagal di tampilkan, combobox template list tidak terisi data
Form Capture Data berhasil di tampilkan, combobox template list terisi dengan data template, datagrid imagelist blank, pictureEdit blank, datagrid result blank √
Open Doc. File Muncul window folder browser,
Window folder browser tidak
Muncul window
setelah memilih folder, image masuk ke datagrid image list. muncul, setelah memilih folder, image tidak masuk ke datagrid image list. setelah memilih folder, image masuk ke datagrid image list.
Memilih doc file di datagrid Image List
Doc file terseleksi, gambar muncul di pictureEdit
Doc file tidak terseleksi, gambar tidak muncul di pictureEdit
Doc file terseleksi, gambar muncul di pictureEdit
√
Memilih Template yang digunakan untuk capture data
Combobox template list berisi data – data template setelah memilih salah satu data maka kolom columnName dan Description datagrid result terisi dengan informasi mapping template Combobox template list tidak berisi data – data template, setelah memilih salah satu data maka kolom datagrid result tidak terisi dengan informasi mapping template
Combobox template list berisi data – data template, setelah memilih salah satu data maka kolom columnName dan Description datagrid result terisi dengan informasi mapping template √ Load Template Mapping Muncul kotak – kotak berwarna merah di pictureEdit kotak – kotak berwarna merah tidak muncul di pictureEdit Muncul kotak – kotak berwarna merah di pictureEdit √ Capture Data Kolom result di datagrid result terisi dengan teks-teks yang
dicapture
Kolom result di datagrid result tidak terisi dengan teks-teks yang dicapture
Kolom result di datagrid result terisi dengan teks-teks yang
dicapture
√
Save Captured Data
Data yang tercapture otomatis masuk ke table Application sesuai dengan mapping kolomya Data yang tercapture tidak masuk ke table Application, data yang masuk tidak sesuai dengan mapping kolom Data yang tercapture otomatis masuk ke table Application sesuai dengan mapping kolomya √
Load Data Form
Berhasil memanggil DataForm, datagrid master terisi dengan data, datagrid detail terisi dengan data
Gagal memanggil DataForm, datagrid master tidak terisi dengan data, datagrid detail tidak terisi dengan data
Berhasil memanggil DataForm, datagrid master terisi dengan data, datagrid detail terisi dengan data
√
data terbaru ke datagrid
data terbaru ke datagrid
oleh data terbaru
View Doc File
Berhasil menampilkan dokumen yang telah dicapture datanya Gagal menampilkan dokumen yang telah dicapture datanya Dokumen berhasil ditampilkan √