          # not possible to distribute them evenly
          num_per_bin = len(img_list) // num_bins
          remainder = len(img_list) % num_bins
  
          logger.info("Grouping by face-yaw...")
          bins = [[] for _ in range(num_bins)]
          idx = 0
          for i in range(num_bins):
              for _ in range(num_per_bin):
                  bins[i].append(img_list[idx][0])
                  idx += 1
  
          # If remainder is 0, nothing gets added to the last bin.
          for i in range(1, remainder + 1):
              bins[-1].append(img_list[-i][0])
  
 
</s> remove         logger.info("Sorting by percentage of black pixels...")
        img_list = [(filename, np.ndarray.all(image == [0, 0, 0], axis=2).sum()/image.size*100*3)
                    for filename, image, _ in tqdm(self._loader.load(),
                                                   desc="Calculating black pixels",
                                                   total=self._loader.count,
                                                   leave=False)]
        img_list_len = len(img_list)
        for i in tqdm(range(0, img_list_len - 1), desc="Comparing black pixels", file=sys.stdout):
            for j in range(0, img_list_len-i-1):
                if img_list[j][1] > img_list[j+1][1]:
                    temp = img_list[j]
                    img_list[j] = img_list[j+1]
                    img_list[j+1] = temp
        return img_list

    # Methods for grouping
    def group_blur(self, img_list):
        """ Group into bins by blur """
        # Starting the binning process
        num_bins = self._args.num_bins

        # The last bin will get all extra images if it's
        # not possible to distribute them evenly
        num_per_bin = len(img_list) // num_bins
        remainder = len(img_list) % num_bins

        logger.info("Grouping by blur...")
        bins = [[] for _ in range(num_bins)]
        idx = 0
        for i in range(num_bins):
            for _ in range(num_per_bin):
                bins[i].append(img_list[idx][0])
                idx += 1

        # If remainder is 0, nothing gets added to the last bin.
        for i in range(1, remainder + 1):
            bins[-1].append(img_list[-i][0])

        return bins

    def group_blur_fft(self, img_list):
        """ Group into bins by fft blur score"""
        # Starting the binning process
        num_bins = self._args.num_bins

        # The last bin will get all extra images if it's
        # not possible to distribute them evenly
        num_per_bin = len(img_list) // num_bins
        remainder = len(img_list) % num_bins

        logger.info("Grouping by fft blur score...")
        bins = [[] for _ in range(num_bins)]
        idx = 0
        for i in range(num_bins):
            for _ in range(num_per_bin):
                bins[i].append(img_list[idx][0])
                idx += 1

        # If remainder is 0, nothing gets added to the last bin.
        for i in range(1, remainder + 1):
            bins[-1].append(img_list[-i][0])

        return bins

    def group_face_cnn(self, img_list):
        """ Group into bins by CNN face similarity """
        logger.info("Grouping by face-cnn similarity...")

        # Groups are of the form: group_num -> reference faces
        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 = []

        # Comparison threshold used to decide how similar
        # faces have to be to be grouped together.
        # It is multiplied by 1000 here to allow the cli option to use smaller
        # numbers.
        min_threshold = self._args.min_threshold * 1000

        img_list_len = len(img_list)
 </s> add         logger.debug("Cleaning arguments: %s", arguments)
        if arguments.sort_method == "none" and arguments.group_method == "none":
            logger.error("Both sort-by and group-by are 'None'. Nothing to do.")
            sys.exit(1) </s> remove         # The last bin will get all extra images if it's
        # not possible to distribute them evenly
        num_per_bin = len(img_list) // num_bins
        remainder = len(img_list) % num_bins
 </s> add         arguments = self._set_output_folder(arguments) </s> remove         # If remainder is 0, nothing gets added to the last bin.
        for i in range(1, remainder + 1):
            bins[-1].append(img_list[-i][0])
 </s> add         logger.debug("Cleaned arguments: %s", arguments)
        return arguments </s> remove         return bins
 </s> add     def _get_sorter(self) -> "SortMethod":
        """ Obtain a sorter/grouper combo for the selected sort/group by options </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("-", "_")
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
          # not possible to distribute them evenly
          num_per_bin = len(img_list) // num_bins
          remainder = len(img_list) % num_bins
  
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
        if arguments.log_changes and arguments.log_file_path == "sort_log.json":
            # Assign default sort_log.json value if user didn't specify one
            arguments.log_file_path = os.path.join(self._args.input_dir, 'sort_log.json')
  
          # If remainder is 0, nothing gets added to the last bin.
          for i in range(1, remainder + 1):
              bins[-1].append(img_list[-i][0])
  
keep keep keep keep replace replace replace replace replace replace 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