<?php
session_start();
include "../../inc/config.php";
$config_feeder = $db->fetch_single_row('config_user','id',1);
$id_sp = $config_feeder->id_sp;
$user_id = $config_feeder->id_user;
$json_response = array();
$jumlah = array();
if ($_POST['total_data']>0) {
		$url_rest = get_service_url('rest');

		$offset = $_POST['offset'];
		$token = $_POST['token'];

		$jumlah['offset'] = $offset;
		$jumlah['token'] = $_POST['token'];

		if ($offset==0) {
			$token = get_token();
		    $jumlah['token'] = $token;
		}

		$sem = "";
		$query_matkul = "";
		$query_kelas  = "";
		$jurusan = "";
		$status_data  = "";
		$query_not_in = "";
		$nim_concat = array();
		$nim_sms_concat = array();
		$data_loop_kelas = array();
		$id_kelas_where = array();
		$id_kelas_feeder = array();
		$nim_data = array();
		$id_kls_reg_pd = array();
		$error_code = "";
		$data_krs = array();
		$data_ids = array();
		$error_update_data = array();
		$data_id_error = array();
		$data_nim = array();
		$update_data = array();
		$data_id_sukses = array();
		$data_id_sukses_restore = array();
		$data_krs_update = array();
		$data_ids_up = array();
		$jumlah_sukses = 0;
		$jumlah_error = 0;
		$all_errors = array();
		$msg = "";
		$all_id = array();
		$all_krs_nilai = array();
		$id_kls_reg_pd_error = array();
		$data_krs_nilai = array();

		$data_update_nilai = array();
		$data_id_update_nilai = array();
		$data_update_nilai_temp = array();
		$data_nilai_temp_restore = array();
		$data_nilai = array();
		$data_nilai_temp_restore_final = array();
		$data_nilai_sukses_restore = array();
		$data_id_final = array();


    	if ($_POST['sem']!='all') {
      		$sem = "and nilai.semester='".$_POST['sem']."'";
    	}

		if ($_POST['matkul']!='all') {
			$query_matkul = "and kode_mk='".$_POST['matkul']."'";
		}
		if ($_POST['kelas']!='all') {
			$query_kelas  = "and nama_kelas='".$_POST['kelas']."'";
		}
		
		if ($_POST['jurusan']!='all') {
			$jurusan = "and trim(nilai.kode_jurusan_kelas)='".trim($_POST['jurusan'])."'";
		} else {
			if ($_SESSION['level']!=1) {
				$jurusan = "and trim(nilai.kode_jurusan_kelas)='".$_SESSION['jurusan']."'";
			}
		}

		  if ($_POST['status_data']!='all') {
		    $status_data  = "and status_error='".$_POST['status_data']."'";
		  } else {
		    $status_data  = "and status_error!=1";
		  }

		 $query_not_in = "and unik_id not in(".$_POST['random_number'].")"; ;

		$data_for_id_kelas = $db->fetch_custom("select nilai.*,jurusan.id_sms as id_sms_kelas,nilai.id as id_krs,
		(select id_sms from jurusan where jurusan.kode_jurusan=nilai.kode_jurusan) as id_sms_mhs from nilai inner join jurusan on nilai.kode_jurusan_kelas=jurusan.kode_jurusan
		 where nilai.id is not null $sem $jurusan $status_data $query_matkul $query_kelas $query_not_in limit 99");

		
		foreach ($data_for_id_kelas as $dt_id) {
			//$id_kelas_array[] = $dt_id->id_krs;
			//$nim_concat[convert_ascii($dt_id->nim)] = "('".$dt_id->nim."')";
			//$nim_sms_concat[convert_ascii($dt_id->nim)] = "('".$dt_id->nim."','".$dt_id->id_sms_mhs."')";
			$kode_mk_like[$dt_id->kode_mk] = "kode_mata_kuliah like '%$dt_id->kode_mk%'";
			$nim_like[$dt_id->nim] = "nim like '%$dt_id->nim%'";
			$sms_and[$dt_id->id_sms_mhs] = "('".$dt_id->id_sms_mhs."')";
			$sms_and_kelas[$dt_id->id_sms_kelas] = "('".$dt_id->id_sms_kelas."')";
			$nama_kelas_like[$dt_id->nama_kelas] = "nama_kelas_kuliah like '%$dt_id->nama_kelas%'";
			$id_semester_in[$dt_id->semester] = "('".$dt_id->semester."')";
			$data_loop_kelas[] = $dt_id;
			$id_kelas_where[$dt_id->id_sms_kelas.trim($dt_id->kode_mk).trim($dt_id->nama_kelas).$dt_id->semester] = "('".$dt_id->id_sms_kelas."','".trim($dt_id->kode_mk)."','".trim($dt_id->nama_kelas)."','".trim($dt_id->semester)."')";

			//check periode
			//$periode_concat[convert_ascii($dt_id->id_sms).convert_ascii($dt_id->semester)] = "('".$dt_id->id_sms."','".$dt_id->semester."')";

		}



		$implode_prodi = implode(",",$sms_and);
		$implode_id_kelas = implode(",", $id_kelas_where);
		$implode_sms_kelas = implode(",", $sms_and_kelas);
		$implode_semester = implode(",", $id_semester_in);
		$implode_nama_kelas_like = implode(" or ",$nama_kelas_like);
		$implode_kode_mk_like = implode(" or ",$kode_mk_like);

		$data_krs_mhs = array();
		
		if ($_POST['metode']=='in_skip') {
			$implode_nim_like = implode(" or ",$nim_like);
			
			$kelas_filter = "id_prodi in($implode_sms_kelas) and id_semester in($implode_semester) and ($implode_kode_mk_like) and ($implode_nim_like)";
			$data_req_kelas = [
				'act' => 'GetDetailNilaiPerkuliahanKelas',
			    'token' => $token,
			    'filter' => $kelas_filter,
			    'order' => "",
			    'limit' => "",
			    'offset' => ""

			];
			$check_krs_kelas_exist = json_decode($db->run($data_req_kelas,$url_rest));
			//dump($check_krs_kelas_exist);
			if (!empty($check_krs_kelas_exist->data)) {
				foreach ($check_krs_kelas_exist->data as $dt_id_kelas) {
				
				$data_krs_mhs[$dt_id_kelas->id_prodi.convert_ascii($dt_id_kelas->kode_mata_kuliah).convert_ascii($dt_id_kelas->nim).convert_ascii($dt_id_kelas->id_semester)] = $dt_id_kelas->id_kelas_kuliah;
				}
			}

		} else {
			$kelas_filter = "id_prodi in($implode_sms_kelas) and id_semester in($implode_semester) and ($implode_kode_mk_like) and ($implode_nama_kelas_like)";
			$data_req_kelas = [
				'act' => 'GetDetailKelasKuliah',
			    'token' => $token,
			    'filter' => $kelas_filter,
			    'order' => "",
			    'limit' => "",
			    'offset' => ""

			];
			$check_kelas_exist = json_decode($db->run($data_req_kelas,$url_rest));
		/*	dump($data_req_kelas);
			dump($check_kelas_exist);
			exit();*/
			if (!empty($check_kelas_exist->data)) {
				foreach ($check_kelas_exist->data as $dt_id_kelas) {
				
				$id_kelas_feeder[$dt_id_kelas->id_prodi.convert_ascii($dt_id_kelas->kode_mata_kuliah).convert_ascii($dt_id_kelas->nama_kelas_kuliah).convert_ascii($dt_id_kelas->id_semester)] = $dt_id_kelas->id_kelas_kuliah;
				}
			}
		}

//dump($data_krs_mhs);
				//dump($dt_id_kelas);
			//dump($id_kelas_where);
/*			$implode_periode = implode(",", $periode_concat);
			$filter_periode = "(id_prodi,trim(periode_pelaporan)) IN ($implode_periode)";
			$data_dic = [
				'act' => 'GetPeriode',
			    'token' => $token,
			    'filter' => $filter_periode
			];
			$data_periode = array();
			$check_periode = service_request($data_dic);
			if (!empty($check_periode->data)) {
				foreach ($check_periode->data as $periode) {
					$data_periode[$periode->id_prodi.$periode->periode_pelaporan] = $periode->tipe_periode;
				}
			}

			$filter_periode = "(id_program_studi,trim(id_semester)) IN ($implode_periode)";
			$data_dic = [
				'act' => 'GetPeriodeLampau',
			    'token' => $token,
			    'filter' => $filter_periode
			];
			$check_periode_lampau = service_request($data_dic);
			$data_periode_lampau = array();
			if (!empty($check_periode_lampau->data)) {
				foreach ($check_periode_lampau->data as $pr) {
					$data_periode_lampau[$pr->id_program_studi.$pr->id_semester] = $pr->tipe_periode;
				}
			}

			$merge_periode = array();

			$merge_periode = array_merge($data_periode,$data_periode_lampau);*/

			//dump($merge_periode);

/*		if ($_POST['metode_prodi']=='1') {
			$nim_concat_where = implode(",", $nim_sms_concat);
			$filter_mhs = "(id_prodi,trim(nim)) in ($nim_concat_where)";
		} else {
			$nim_concat_where = implode(",", $nim_concat);
			$filter_mhs = "trim(nim) in ($nim_concat_where)";
		}*/
		//$nim_concat_where = implode(",", $nim_sms_concat);
		$implode_nim_like = implode(" or ",$nim_like);
		
		//$filter_mhs = "(regexp_replace(trim(nim), '[^[:alnum:]\s.]+', ''), id_prodi) in ($nim_concat_where)";
		//$filter_mhs = "(trim(nim),id_prodi) in ($nim_concat_where)";
		$data_req_mhs = [
			'act' => 'GetListMahasiswa',
		    'token' => $token,
		    //'filter' => $filter_mhs,
		    'filter' => "id_registrasi_mahasiswa is not null and ($implode_nim_like) and id_prodi in($implode_prodi)",
		    'order' => "",
		    'limit' => "",
		    'offset' => ""

		];

		$nim_data_keluar = array();
		$check_nim_exist = json_decode($db->run($data_req_mhs,$url_rest));

	/*	dump($data_req_mhs);
		dump($check_nim_exist);
*/
		if (!empty($check_nim_exist->data)) {
			foreach ($check_nim_exist->data as $nim_mhs) {
				//dump($nim_data);
				$nim_data[convert_ascii($nim_mhs->nim).'n'] = $nim_mhs->id_registrasi_mahasiswa;
			
			}
		}
		//dump($nim_data);

function insertKrsNativeArray($data)
{
    global $id_sp;
    global $user_id;
    $datas = array(
	    	'id_kls' => $data['id_kelas_kuliah'],
	    	'id_reg_pd' => $data['id_registrasi_mahasiswa'],
	    	'a_id_reg_pd' => true
    );
    return $datas;
}

function insertKrsNative($data) {
    global $config_feeder;
    global $token;
    $return_data = array();
    $url = $config_feeder->url.':'.$config_feeder->port.'/ws/kelas/updatekrs';
    $insert_reg = service_native($data,$url);
/*     dump($data);
    dump($insert_reg);*/
    return $insert_reg;

}
/*
function insertKrsNativeArray($data)
{
    global $id_sp;
    global $user_id;
    $datas = array(
	    	'id_kls' => $data['id_kelas_kuliah'],
	    	'id_reg_pd' => $data['id_registrasi_mahasiswa'],
	    	//'a_id_reg_pd' => true
    );
    return $datas;
}*/
/*function insertKrsNative($data) {
    global $config_feeder;
    global $token;
    $return_data = array();
    $url = $config_feeder->url.':'.$config_feeder->port.'/ws/krs_mahasiswa/add';
    $insert_reg = service_native($data,$url);
     dump($data);
    dump($insert_reg);
    return $insert_reg;

}
function insertKrsNativeArray($data)
{
    global $id_sp;
    global $user_id;

    $datas = [
        "class" => array(
        	array(
	        	'id_kls' => $data['id_kelas_kuliah'],
	        	'choosed' => true
        	)
        ),
        "nim" => array(
        	'total_data' => 1,
        	'id_reg_pd' => $data['id_registrasi_mahasiswa']
        ),
    ];
    return $datas;
}*/
/*function insertKrsNative($data) {
    global $config_feeder;
    global $token;
    $return_data = array();
    $url = $config_feeder->url.':'.$config_feeder->port.'/ws/kelas/add/mahasiswa';
    $insert_reg = service_native($data,$url);
    //dump($insert_reg);
    return $insert_reg;

}*/

function updateNilaiNativeArray($data)
{
    global $id_sp;
    global $user_id;
    $datas = array(
    	//array(
	    	'id_kls' => $data['id_kelas_kuliah'],
	    	'id_reg_pd' => $data['id_registrasi_mahasiswa'],
	    	'nilai_angka_masking' => $data['nilai_angka'],
	        'filter_nilai_huruf' => array(
	        	'nilai_indeks' => $data['nilai_huruf']."#".$data['nilai_indeks']
	        )
	  //  )
    );
    return $datas;
}

function updateNilaiNative($data) {
    global $config_feeder;
    global $token;
    $return_data = array();
    $url = $config_feeder->url.':'.$config_feeder->port.'/ws/nilai/update';
    $insert_reg = service_native($data,$url);
    //dump($data);
    //dump($insert_reg);
    return $insert_reg;

}
function responseCheckNative($data) {
	
	$return_array = array();
	$return_array['data'] = array();
	$return_array['is_error'] = 1;
	
	if (isset($data->message)) {
		if ($data->code=='200') {
			$return_array['is_error'] = 0;
			$return_array['data'] = array(
				'keterangan' => '',
				'status_error' => 1
			);
		} else {
			$return_array['data'] = array(
				'keterangan' => $data->message,
				'status_error' => 2
			);
		}
	} else {
			$return_array['data'] = array(
				'keterangan' => 'Error, Pastikan format nilai sesuai template',
				'status_error' => 2
			);
	}

	
//dump($data);
	return $return_array;
}
	$native_array_data = array();
	$ids_data = array();
	$kls_reg = array();
	$data_insert_krs = array();
	$update_nilai_request = array();
	$data_id = array();
	$krs_native_array = array();
		foreach ($data_loop_kelas as $value) {

			$nim = convert_ascii($value->nim).'n';
			$kode_mk = trim($value->kode_mk);
			$kelas = trim($value->nama_kelas);
			$semester = $value->semester;
			$id_sms = trim($value->id_sms_kelas);

			if ($_POST['metode']=='in_skip') {
				if (in_array($value->id_sms_kelas.convert_ascii($kode_mk).convert_ascii($value->nim).convert_ascii($semester), array_keys($data_krs_mhs))) {
					$id_reg_pd = $nim_data[$nim];
				$id_kls = $data_krs_mhs[$id_sms.$kode_mk.$value->nim.$semester];

				$key_update['id_registrasi_mahasiswa'] =  $id_reg_pd;
								$key_update['id_kelas_kuliah'] = $id_kls;
								$record_update = array(
									'nilai_angka' => $value->nilai_angka,
									'nilai_huruf' => $value->nilai_huruf,
									'nilai_indeks' => $value->nilai_indek
								);
								  $data_dic = [
								      'act' => 'UpdateNilaiPerkuliahanKelas',
								      'key' => $key_update,
								        'token' => $token,
								        'record' => $record_update,
								    ];
								$update_nilai = service_request($data_dic);
								/*dump($data_dic);
								dump($update_nilai);
								exit();*/
								$value_data = addslashes($update_nilai->error_desc);
								if ($value_data!='') {
									$error_update_data[] = array(
										'keterangan' => $value_data,
										'status_error' => 2
									);
									$data_id_error[] = $value->id_krs;
								} else {
									$update_data[] = array(
										'keterangan' => '',
										'status_error' => 1
									);
									$data_id_sukses[] = $value->id_krs;
								}
				} else {
					$error_update_data[] = array(
							'keterangan' => "KRS Mahasiswa belum ada di NEO",
							'status_error' => 2
						);
						$data_id_error[] = $value->id_krs;
				}
				
			} else {
				$kelas_nilai_id = $value->id_sms_kelas.convert_ascii($kode_mk).convert_ascii($kelas).convert_ascii($semester);
			//check if mhs exist
				if (in_array($nim, array_keys($nim_data))) {
					$id_reg_pd = $nim_data[$nim];
					if (in_array($kelas_nilai_id, array_keys($id_kelas_feeder))) {
						$id_kls = $id_kelas_feeder[$id_sms.$kode_mk.$kelas.$semester];
						if ($value->nilai_huruf=='') {
							$error_update_data[] = array(
								'keterangan' => "Nilai Huruf tidak boleh Kosong",
								'status_error' => 2
							);
							$data_id_error[] = $value->id_krs;
						} elseif ($value->nilai_indek=='') {
							$error_update_data[] = array(
								'keterangan' => "Nilai Indeks tidak boleh Kosong",
								'status_error' => 2
							);
							$data_id_error[] = $value->id_krs;
						} /*elseif (!in_array($sms_periode, array_keys($merge_periode))) {
							$error_update_data[] = array(
								'keterangan' => "Tidak bisa merubah nilai karena Periode tidak aktif",
								'status_error' => 2
							);
							$data_id_error[] = $value->id_krs;
						}*/ else {
							if ($_POST['metode']=='in_krs') {
								$data_krs = array(
									'id_kelas_kuliah' => $id_kls,
									'id_registrasi_mahasiswa' => $id_reg_pd,
									//'asal_data' => 9
									);
								  $data_dic_krs = [
								      'act' => 'InsertPesertaKelasKuliah',
								        'token' => $token,
								        'record' => $data_krs,
								    ];
								$do_insert_krs = service_request($data_dic_krs);
								//dump($do_insert_krs);
							} 
								$key_update['id_registrasi_mahasiswa'] =  $id_reg_pd;
								$key_update['id_kelas_kuliah'] = $id_kls;
								$record_update = array(
									'nilai_angka' => $value->nilai_angka,
									'nilai_huruf' => $value->nilai_huruf,
									'nilai_indeks' => $value->nilai_indek
								);
								  $data_dic = [
								      'act' => 'UpdateNilaiPerkuliahanKelas',
								      'key' => $key_update,
								        'token' => $token,
								        'record' => $record_update,
								    ];
								$update_nilai = service_request($data_dic);
								/*dump($data_dic);
								dump($update_nilai);
								exit();*/
								$value_data = addslashes($update_nilai->error_desc);
								if ($value_data!='') {
									$error_update_data[] = array(
										'keterangan' => $value_data,
										'status_error' => 2
									);
									$data_id_error[] = $value->id_krs;
								} else {
									$update_data[] = array(
										'keterangan' => '',
										'status_error' => 1
									);
									$data_id_sukses[] = $value->id_krs;
								}
						}
					} else {
						$error_update_data[] = array(
							'keterangan' => "Pastikan Kelas Sudah Dibuat",
							'status_error' => 2
						);
						$data_id_error[] = $value->id_krs;
					}

				} else {
					$error_update_data[] = array(
						'keterangan' => "Nim Mahasiswa ini tidak ditemukan di feeder",
						'status_error' => 2
					);
					$data_id_error[] = $value->id_krs;
				}
			}
			
			$all_id[] = $value->id_krs;
			$id_kls = "";
			$id_reg_pd = "";
		}

		
		//update error
		if (!empty($error_update_data)) {
			updateMulti('nilai',$error_update_data,'id',$data_id_error);
		}
		$error_update_data = array();
		$data_id_error = array();
		//update sukses
		if (!empty($update_data)) {
			updateMulti('nilai',$update_data,'id',$data_id_sukses);
		}

		$data_reg_kls = array();
/*		if (!empty($kls_reg)) {
			$implode_reg_kls = implode(",", $kls_reg);
			//check if krs exist
		  	$data_dic = [
		      'act' => 'GetKRSMahasiswa',
		      'token' => $token,
		      'filter' => "(id_kelas,id_registrasi_mahasiswa) in($implode_reg_kls)"
		    ];
		    $check_reg_kls = service_request($data_dic);
		    if (!empty($check_reg_kls->data)) {
		    	foreach ($check_reg_kls->data as $dt) {
		    		$data_reg_kls[] = $dt->id_kelas.$dt->id_registrasi_mahasiswa;
		    	}
		    }
		}*/



		//dump($data_reg_kls);

		//loop nilai
		/*if (!empty($data_nilai)) {
			foreach ($data_nilai as $key => $nilai) {
				if (!in_array($nilai['id_kelas_kuliah'].$nilai['id_registrasi_mahasiswa'], $data_reg_kls)) {
					$req_nilai = array(
									'id_registrasi_mahasiswa' => $nilai['id_registrasi_mahasiswa'],
									'id_kelas_kuliah' => $nilai['id_kelas_kuliah'],
									'nilai_angka' => $nilai['nilai_angka'],
									'nilai_huruf' => $nilai['nilai_huruf'],
									'nilai_indeks' => $nilai['nilai_indeks']
								);
					$update_nilai_request[] = updateNilaiNativeArray($req_nilai);
					$data_id[] = $ids_data[$key];
				} else {
					$error_update_data[] = array(
						'keterangan' => "Krs Belum ada di Feeder",
						'status_error' => 2
					);
					$data_id_error[] = $ids_data[$key];
				}
			}
		}*/
		//dump($update_nilai_request);
		//update error
/*		if (!empty($error_update_data)) {
			updateMulti('nilai',$error_update_data,'id',$data_id_error);
		}
		$error_update_data = array();
		$data_id_error = array();*/

		if (!empty($data_insert_krs)) {
			$insert_native_array = insertKrsNativeArray($data_insert_krs);
		}



		$is_error_krs = 0;
		if (!empty($krs_native_array)) {
			$id_implode = implode(",", $ids_data);
			$insert_krs = insertKrsNative($ins_krs);
			$check_responses = responseCheckNative($insert_krs);
	    	if ($check_responses['is_error']!=0) {
	    		$db->fetch_custom("update nilai set status_error='2',keterangan='".$check_responses['data']['keterangan']."' where id in($id_implode)");
	    		$is_error_krs = 1;
	    	}
/*			foreach ($krs_native_array as $ins_krs) {
				$insert_krs = insertKrsNative($ins_krs);
				$check_responses = responseCheckNative($insert_krs);
		    	if ($check_responses['is_error']!=0) {
		    		$db->fetch_custom("update nilai set status_error='2',keterangan='".$check_responses['data']['keterangan']."' where id in($id_implode)");
		    		$is_error_krs = 1;
		    	}
			}*/


	    	//if ($is_error_krs==0) {
				if (!empty($update_nilai_request)) {
					$id_implode = implode(",", $ids_data);
					$update_nilai_request = updateNilaiNative($update_nilai_request);
					$check_responsed = responseCheckNative($update_nilai_request);
			    	if ($check_responsed['is_error']==0) {
			    		$db->fetch_custom("update nilai set status_error='1' where id in($id_implode)");
			    	} else {
			    		$db->fetch_custom("update nilai set status_error='2',keterangan='".$check_responsed['data']['keterangan']."' where id in($id_implode)");
			    	}
				}
	    	//}

		}

		$update_data = array();
		$data_id_sukses = array();

		$implode_id = implode(",", $all_id);
		
		$db->fetch_custom("update nilai set unik_id=".$_POST['random_number']." where id in (".$implode_id.")");

	if (isset($_POST['id_data'])) {

		$jml_error_sukses = $db->fetch_custom_single("SELECT COUNT(IF(status_error='1',1,NULL)) AS jml_sukses,COUNT(IF(status_error='2',1,NULL)) AS jml_error FROM nilai where unik_id=".$_POST['random_number']);

		$jumlah_sukses = $jml_error_sukses->jml_sukses;
		$jumlah_error = $jml_error_sukses->jml_error;

		$db->fetch_custom("update nilai set unik_id=0 where  unik_id=".$_POST['random_number']);
		
		$msg =  "<div class=\"alert alert-warning \" role=\"alert\">
		<font color=\"#3c763d\">".$jumlah_sukses." data Nilai berhasil ditambah</font><br />
		<font color=\"#ce4844\" >".$jumlah_error." data tidak bisa ditambahkan </font>";
		
		if (!$jumlah_error==0) {
			$msg .= "<a data-toggle=\"collapse\" href=\"#collapseExample\" aria-expanded=\"false\" aria-controls=\"collapseExample\">Detail error</a>";

			$all_errors = array('Silakan lihat detail error di list data');
			
		}
		//echo "<br />Total: ".$i." baris data";
		$msg .= "<div class=\"collapse\" id=\"collapseExample\">";
				$i=1;
				foreach ($all_errors as $pesan) {
						$msg .= "<div class=\"bs-callout bs-callout-danger\">".$pesan."</div><br />";
					$i++;
					}
		$msg .= "</div>
		</div>";


		$jumlah['last_notif'] = $msg;
	}


} else {
	$msg =  "Tidak ada data yang bisa diproses<p>";
		$jumlah['last_notif'] = $msg;
}

array_push($json_response, $jumlah);
echo json_encode($json_response);
//echo convert(memory_get_usage(true)); // 123 kb