              else:
                  reference_groups[len(reference_groups)] = [img_list[i][1]]
                  bins.append([img_list[i][0]])
  
          return bins
  
      # Final process methods
      def final_process_rename(self, img_list):
          """ Rename the files """
          output_dir = self._args.output_dir
 
</s> remove         logger.info("Grouping by percentage of black pixels...")

        # Starting the binning process
        bins = [[] for _ in range(self._args.num_bins)]
        # Get edges of bins from 0 to 100
        bins_edges = self._near_split(100, self._args.num_bins)
        # Get the proper bin number for each img order
        img_bins = np.digitize([x[1] for x in img_list], bins_edges, right=True)

        # Place imgs in bins
        for idx, _bin in enumerate(img_bins):
            bins[_bin].append(img_list[idx][0])

        return bins

    def group_hist(self, img_list):
        """ Group into bins by histogram """
        logger.info("Grouping by histogram...")

        # Groups are of the form: group_num -> reference histogram
        reference_groups = {}

        # Bins array, where index is the group number and value is
        # an array containing the file paths to the images in that group
        bins = []

        min_threshold = self._args.min_threshold

        img_list_len = len(img_list)
        reference_groups[0] = [img_list[0][1]]
        bins.append([img_list[0][0]])

        for i in tqdm(range(1, img_list_len),
                      desc="Grouping",
                      file=sys.stdout):
            current_best = [-1, float("inf")]
            for key, value in reference_groups.items():
                score = self.get_avg_score_hist(img_list[i][1], value)
                if score < current_best[1]:
                    current_best[0], current_best[1] = key, score

            if current_best[1] < min_threshold:
                reference_groups[current_best[0]].append(img_list[i][1])
                bins[current_best[0]].append(img_list[i][0])
            else:
                reference_groups[len(reference_groups)] = [img_list[i][1]]
                bins.append([img_list[i][0]])
 </s> add         sort_method = self._args.sort_method
        group_method = self._args.group_method </s> remove     # Final process methods
    def final_process_rename(self, img_list):
        """ Rename the files """
        output_dir = self._args.output_dir

        process_file = self.set_process_file_method(self._args.log_changes,
                                                    self._args.keep_original)

        # Make sure output directory exists
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        description = (
            "Copying and Renaming" if self._args.keep_original
            else "Moving and Renaming"
        )

        for i in tqdm(range(0, len(img_list)),
                      desc=description,
                      leave=False,
                      file=sys.stdout):
            src = img_list[i] if isinstance(img_list[i], str) else img_list[i][0]
            src_basename = os.path.basename(src)

            dst = os.path.join(output_dir, f"{i:05d}_{src_basename}")
            try:
                process_file(src, dst, self.changes)
            except FileNotFoundError as err:
                logger.error(err)
                logger.error('fail to rename %s', src)

        for i in tqdm(range(0, len(img_list)),
                      desc=description,
                      file=sys.stdout):
            renaming = self.set_renaming_method(self._args.log_changes)
            fname = img_list[i] if isinstance(img_list[i], str) else img_list[i][0]
            src, dst = renaming(fname, output_dir, i, self.changes)

            try:
                os.rename(src, dst)
            except FileNotFoundError as err:
                logger.error(err)
                logger.error('fail to rename %s', format(src))

        if self._args.log_changes:
            self.write_to_log(self.changes)

    def final_process_folders(self, bins):
        """ Move the files to folders """
        output_dir = self._args.output_dir
 </s> add         if sort_method != "none" and group_method != "none" and group_method != sort_method:
            grouper = self._processes[group_method](self._args, is_group=True)
            retval = SortMultiMethod(self._args, sorter, grouper)
            logger.debug("Got sorter + grouper: %s (%s, %s)", retval, sorter, grouper) </s> remove         for i in tqdm(range(0, img_list_len - 1),
                      desc="Grouping",
                      file=sys.stdout):
            fl1 = img_list[i][1]

            current_best = [-1, float("inf")]

            for key, references in reference_groups.items():
                try:
                    score = self.get_avg_score_faces_cnn(fl1, references)
                except TypeError:
                    score = float("inf")
                except ZeroDivisionError:
                    score = float("inf")
                if score < current_best[1]:
                    current_best[0], current_best[1] = key, score

            if current_best[1] < min_threshold:
                reference_groups[current_best[0]].append(fl1[0])
                bins[current_best[0]].append(img_list[i][0])
            else:
                reference_groups[len(reference_groups)] = [img_list[i][1]]
                bins.append([img_list[i][0]])

        return bins

    def group_face_yaw(self, img_list):
        """ Group into bins by yaw of face """
        # Starting the binning process
        num_bins = self._args.num_bins
 </s> add         # Prepare sort, group and final process method names
        arguments.sort_method = arguments.sort_method.lower().replace("-", "_")
        arguments.group_method = arguments.group_method.lower().replace("-", "_") </s> remove         if log_changes:
            if keep_original:
                def process_file(src, dst, changes):
                    """ Process file method if logging changes
                        and keeping original """
                    copyfile(src, dst)
                    changes[src] = dst

            else:
                def process_file(src, dst, changes):
                    """ Process file method if logging changes
                        and not keeping original """
                    os.rename(src, dst)
                    changes[src] = dst

        else:
            if keep_original:
                def process_file(src, dst, changes):  # pylint: disable=unused-argument
                    """ Process file method if not logging changes
                        and keeping original """
                    copyfile(src, dst)

            else:
                def process_file(src, dst, changes):  # pylint: disable=unused-argument
                    """ Process file method if not logging changes
                        and not keeping original """
                    os.rename(src, dst)
        return process_file

    @staticmethod
    def set_renaming_method(log_changes):
        """ Set the method for renaming files """
        if log_changes:
            def renaming(src, output_dir, i, changes):
                """ Rename files  method if logging changes """
                src_basename = os.path.basename(src)

                __src = os.path.join(output_dir,
                                     f"{i:05d}_{src_basename}")
                dst = os.path.join(
                    output_dir,
                    f"{i:05d}{os.path.splitext(src_basename)[1]}")
                changes[src] = dst
                return __src, dst
        else:
            def renaming(src, output_dir, i, changes):  # pylint: disable=unused-argument
                """ Rename files method if not logging changes """
                src_basename = os.path.basename(src)

                src = os.path.join(output_dir,
                                   f"{i:05d}_{src_basename}")
                dst = os.path.join(
                    output_dir,
                    f"{i:05d}{os.path.splitext(src_basename)[1]}")
                return src, dst
        return renaming
 </s> add         output_dir = self._args.output_dir
        os.makedirs(output_dir, exist_ok=True) </s> remove         process_file = self.set_process_file_method(self._args.log_changes,
                                                    self._args.keep_original)

        # First create new directories to avoid checking
        # for directory existence in the moving loop
        logger.info("Creating group directories.")
        for i in range(len(bins)):
            directory = os.path.join(output_dir, str(i))
            if not os.path.exists(directory):
                os.makedirs(directory)

        description = (
            "Copying into Groups" if self._args.keep_original
            else "Moving into Groups"
        )

        logger.info("Total groups found: %s", len(bins))
        for i in tqdm(range(len(bins)), desc=description, file=sys.stdout):
            for j in range(len(bins[i])):
                src = bins[i][j]
                src_basename = os.path.basename(src)
 </s> add         else:
        sort_method = group_method if sort_method == "none" else sort_method
        sorter = self._processes[sort_method](self._args,
                                              is_group=self._args.sort_method == "none")
              else:
                  reference_groups[len(reference_groups)] = [img_list[i][1]]
                  bins.append([img_list[i][0]])
  
        sort_method = group_method if sort_method == "none" else sort_method
        sorter = self._processes[sort_method](self._args,
                                              is_group=self._args.sort_method == "none")
  
      # Final process methods
      def final_process_rename(self, img_list):
          """ Rename the files """
          output_dir = self._args.output_dir
keep keep keep keep replace keep keep keep keep keep
 Overhaul sort:
  - Standardize image data reading and writing
  - Optimize loading (just one pass required)
  - Make all sort groups binnable (to greater or lesser results)
  - Add sort by pitch
  - Deprecate multiple options
  - linting, docs + locales 
tools/sort/sort.py