text: # -*- coding: utf-8 -*-
  
  import os
  import json
  from json import encoder
  from sklearn_porter.estimator.classifier.Classifier import Classifier
  
  
  class KNeighborsClassifier(Classifier):
      """
      See also
      --------
      sklearn.neighbors.KNeighborsClassifier
  
      http://scikit-learn.org/stable/modules/generated/
      sklearn.neighbors.KNeighborsClassifier.html
      """
  
      SUPPORTED_METHODS = ['predict']
  
      # @formatter:off
      TEMPLATES = {
          'java': {
              'type':     '{0}',
              'arr':      '{{{0}}}',
              'arr[]':    '{type}[] {name} = {{{values}}};',
              'arr[][]':  '{type}[][] {name} = {{{values}}};',
              'indent':   '    ',
          },
          'js': {
              'type':     '{0}',
              'arr':      '[{0}]',
              'arr[]':    'var {name} = [{values}];',
              'arr[][]':  'var {name} = [{values}];',
              'indent':   '    ',
          },
      }
      # @formatter:on
  
      def __init__(self, estimator, target_language='java',
                   target_method='predict', **kwargs):
          """
          Port a trained estimator to the syntax of a chosen programming
          language.
  
          Parameters
          ----------
          :param estimator : KNeighborsClassifier
              An instance of a trained KNeighborsClassifier estimator.
          :param target_language : string, default: 'java'
              The target programming language.
          :param target_method : string, default: 'predict'
              The target method of the estimator.
          """
          super(KNeighborsClassifier, self).__init__(
              estimator, target_language=target_language,
              target_method=target_method, **kwargs)
  
          if estimator.weights != 'uniform':
              msg = "Only 'uniform' weights are supported for this classifier."
              raise NotImplementedError(msg)
  
          self.estimator = estimator
  
      def export(self, class_name, method_name, export_data=False,
                 export_dir='.', export_filename='data.json',
                 export_append_checksum=False, **kwargs):
          """
          Port a trained estimator to the syntax of a chosen programming language.
  
          Parameters
          ----------
          :param class_name : string
              The name of the class in the returned result.
          :param method_name : string
              The name of the method in the returned result.
          :param export_data : bool, default: False
              Whether the model data should be saved or not.
          :param export_dir : string, default: '.' (current directory)
              The directory where the model data should be saved.
          :param export_filename : string, default: 'data.json'
              The filename of the exported model data.
          :param export_append_checksum : bool, default: False
              Whether to append the checksum to the filename or not.
  
          Returns
          -------
          :return : string
              The transpiled algorithm with the defined placeholders.
          """
          # Arguments:
          self.class_name = class_name
          self.method_name = method_name
  
          # Estimator:
          est = self.estimator
  
          # Basic parameters:
          self.metric = est.metric
          self.n_classes = len(est.classes_)
          self.n_templates = len(est._fit_X)  # pylint: disable=W0212
          self.n_features = len(est._fit_X[0])  # pylint: disable=W0212
          self.n_neighbors = est.n_neighbors
          self.algorithm = est.algorithm
          self.power_param = est.p
  
          if self.algorithm != 'brute':
              from sklearn.neighbors.kd_tree import KDTree  # pylint: disable-msg=E0611
              from sklearn.neighbors.ball_tree import BallTree  # pylint: disable-msg=E0611
              tree = est._tree  # pylint: disable=W0212
              if isinstance(tree, (KDTree, BallTree)):
                  self.tree = tree
  
          if self.target_method == 'predict':
              # Exported:
              if export_data and os.path.isdir(export_dir):
                  self.export_data(export_dir, export_filename,
                                   export_append_checksum)
                  return self.predict('exported')
              # Separated:
              return self.predict('separated')
  
      def export_data(self, directory, filename, with_md5_hash=False):
          """
          Save model data in a JSON file.
  
          Parameters
          ----------
          :param directory : string
              The directory.
          :param filename : string
              The filename.
          :param with_md5_hash : bool, default: False
              Whether to append the checksum to the filename or not.
          """
          model_data = {
              'X': self.estimator._fit_X.tolist(),  # pylint: disable=W0212
              'y': self.estimator._y.tolist(),  # pylint: disable=W0212
              'kNeighbors': self.n_neighbors,
              'nClasses': self.n_classes,
              'power': self.power_param
          }
          encoder.FLOAT_REPR = lambda o: self.repr(o)
          json_data = json.dumps(model_data, sort_keys=True)
          if with_md5_hash:
              import hashlib
              json_hash = hashlib.md5(json_data).hexdigest()
              filename = filename.split('.json')[0] + '_' + json_hash + '.json'
          path = os.path.join(directory, filename)
          with open(path, 'w') as fp:
              fp.write(json_data)
  
      def predict(self, temp_type):
          """
          Transpile the predict method.
  
          Parameters
          ----------
          :param temp_type : string
              The kind of export type (embedded, separated, exported).
  
          Returns
          -------
          :return : string
              The transpiled predict method as string.
          """
          # Exported:
          if temp_type == 'exported':
              temp = self.temp('exported.class')
              return temp.format(class_name=self.class_name,
                                 method_name=self.method_name,
                                 n_features=self.n_features)
          # Separated:
          if temp_type == 'separated':
              meth = self.create_method()
              return self.create_class(meth)
  
      def create_method(self):
          """
          Build the estimator method or function.
  
          Returns
          -------
          :return : string
              The built method as string.
          """
          # Distance computation
          metric_name = '.'.join(['separated', 'metric', self.metric])
          distance_comp = self.temp(metric_name, n_indents=1, skipping=True)
  
          temp_method = self.temp('separated.method.predict', n_indents=1,
                                  skipping=True)
          return temp_method.format(class_name=self.class_name,
                                    method_name=self.method_name,
                                    distance_computation=distance_comp)
  
      def create_class(self, method):
          """
          Build the estimator class.
  
          Returns
          -------
          :return : string
              The built class as string.
          """
          temp_type = self.temp('type')
          temp_arr = self.temp('arr')
          temp_arr_ = self.temp('arr[]')
          temp_arr__ = self.temp('arr[][]')
  
          # Samples:
          temps = []
          for atts in enumerate(self.estimator._fit_X):  # pylint: disable=W0212
              tmp = [temp_type.format(self.repr(a)) for a in atts[1]]
              tmp = temp_arr.format(', '.join(tmp))
              temps.append(tmp)
          temps = ', '.join(temps)
          temps = temp_arr__.format(type='double', name='X', values=temps,
                                    n=self.n_templates, m=self.n_features)
  
          # Classes:
          classes = self.estimator._y  # pylint: disable=W0212
          classes = [temp_type.format(int(c)) for c in classes]
          classes = ', '.join(classes)
          classes = temp_arr_.format(type='int', name='y', values=classes,
                                     n=self.n_templates)
  
          temp_class = self.temp('separated.class')
          return temp_class.format(class_name=self.class_name,
                                   method_name=self.method_name, method=method,
                                   n_features=self.n_features, X=temps, y=classes,
                                   n_neighbors=self.n_neighbors,
                                   n_templates=self.n_templates,
                                   n_classes=self.n_classes,
                                   power=self.power_param)
  