code: def block_splitter(items, max_weight, weight=lambda item: 1, key=nokey):
      
      if max_weight <= 0:
          raise ValueError('max_weight=%s' % max_weight)
      ws = WeightedSequence([])
      prev_key = 'Unspecified'
      for item in items:
          w = weight(item)
          k = key(item)
          if w < 0:  # error
              raise ValueError('The item %r got a negative weight %s!' %
                               (item, w))
          elif ws.weight + w > max_weight or k != prev_key:
              new_ws = WeightedSequence([(item, w)])
              if ws:
                  yield ws
              ws = new_ws
          elif w > 0:  # ignore items with 0 weight
              ws.append((item, w))
          prev_key = k
      if ws:
          yield ws
docs: :param items: an iterator over items
      :param max_weight: the max weight to split on
      :param weight: a function returning the weigth of a given item
      :param key: a function returning the kind of a given item
  
      Group together items of the same kind until the total weight exceeds the
      `max_weight` and yield `WeightedSequence` instances. Items
      with weight zero are ignored.
  
      For instance
  
       >>> items = 'ABCDE'
       >>> list(block_splitter(items, 3))
       [<WeightedSequence ['A', 'B', 'C'], weight=3>, <WeightedSequence ['D', 'E'], weight=2>]
  
      The default weight is 1 for all items. Here is an example leveraning on the
      key to group together results:
  
      >>> items = ['A1', 'C2', 'D2', 'E2']
      >>> list(block_splitter(items, 2, key=operator.itemgetter(1)))
      [<WeightedSequence ['A1'], weight=1>, <WeightedSequence ['C2', 'D2'], weight=2>, <WeightedSequence ['E2'], weight=1>]