function to register finished runs

			Every time a run has finished, this function should be called
			to register it with the result logger. If overwritten, make
			sure to call this method from the base class to ensure proper
			logging.


			Parameters:
			-----------
			job_id: dict
				a dictionary containing all the info about the run
			job_result: dict
				contains all the results of the job, i.e. it's a dict with
				the keys 'loss' and 'info'

def new_result(self, job):
		"""
			function to register finished runs

			Every time a run has finished, this function should be called
			to register it with the result logger. If overwritten, make
			sure to call this method from the base class to ensure proper
			logging.


			Parameters:
			-----------
			job_id: dict
				a dictionary containing all the info about the run
			job_result: dict
				contains all the results of the job, i.e. it's a dict with
				the keys 'loss' and 'info'

		"""

		super(KernelDensityEstimator, self).new_result(job)
		budget = job.kwargs["budget"]
		if budget not in self.configs.keys():
			self.configs[budget] = []
			self.losses[budget] = []

		# We want to get a numerical representation of the configuration in the original space
		conf = ConfigSpace.Configuration(self.configspace, job.kwargs['config'])
		self.configs[budget].append(conf.get_array())
		self.losses[budget].append(job.result['result']["loss"])


		# Check if we have enough data points to fit a KDE
		if len(self.configs[budget]) % self.update_after_n_points == 0:
			train_configs, train_losses = [], []
		
			train_configs.extend(self.configs[budget])
			train_losses.extend(self.losses[budget])

			n = int(self.top_n_percent * len(train_configs) / 100.)
			
			remaining_budgets = list(self.configs.keys())
			remaining_budgets.remove(budget)
			remaining_budgets.sort(reverse=True)


			for b in remaining_budgets:
				if  n >= self.min_points_in_model: break
				train_configs.extend(self.configs[b])
				train_losses.extend(self.losses[b])
				n = int(self.top_n_percent * len(train_configs) / 100.)

			if  len(train_losses) < self.min_points_in_model:
				return
			
			n = max(self.min_points_in_model, n)
			
			# Refit KDE for the current budget
			idx = np.argsort(train_losses)

			train_data = (np.array(train_configs)[idx])[:n]
			self.kde_models[budget] = sm.nonparametric.KDEMultivariate(data=train_data,
																 var_type=self.var_type,
																 bw='cv_ls')