# Path: jcn/util.py
# def clamp(value, min_=None, max_=None):
#     if min_ is None and max_ is None:
#         return value
#     if min_ is None:
#         min_ = min(value, max_)
#     if max_ is None:
#         max_ = max(value, min_)
#     return sorted((value, min_, max_))[1]
# 
# def weighted_round_robin(iterable):
#     '''Takes an iterable of tuples of <item>, <weight> and cycles around them,
#     returning heavier (integer) weighted items more frequently.
#     '''
#     cyclable_list = []
#     assigned_weight = 0
#     still_to_process = [
#         (item, weight) for item, weight in
#         sorted(iterable, key=lambda tup: tup[1], reverse=True)]
#     while still_to_process:
#         for i, (item, weight) in enumerate(still_to_process):
#             if weight > assigned_weight:
#                 cyclable_list.append(item)
#             else:
#                 del still_to_process[i]
#         assigned_weight += 1
#     return cycle(cyclable_list)
# 
# def crop_or_expand(iterable, length, default=' ', scheme='beginning'):
#     if len(iterable) > length:
#         # Crop:
#         if scheme == 'beginning':
#             result = iterable[:length]
#         elif scheme == 'middle':
#             extra = len(iterable) - length
#             result = iterable[extra // 2:-extra // 2]
#         elif scheme == 'end':
#             result = iterable[-length:]
#     elif len(iterable) < length:
#         # Expand:
#         missing = length - len(iterable)
#         try:
#             if scheme == 'beginning':
#                 result = iterable + default * missing
#             elif scheme == 'middle':
#                 result = (default * ((missing + 1) // 2) +
#                           iterable +
#                           default * (missing // 2))
#             elif scheme == 'end':
#                 result = default * missing + iterable
#         except TypeError:
#             raise TypeError(
#                 "Can't expand the given iterable of type {!r} with default "
#                 "value of type {!r}".format(type(iterable), type(default)))
#     else:
#         # Perfect :-)
#         result = iterable[:]
#     return result
# 
# class LoopingCall:
#     def __init__(self, func, *args, **kwargs):
#         self.func = func
#         self.args = args
#         self.kwargs = kwargs
#         self.interval = None
#         self.loop = None
#         self.running = False
# 
#     def start(self, interval, loop=None):
#         self.interval = interval
#         self.loop = loop or asyncio.get_event_loop()
#         self.running = True
#         self._execute()
# 
#     def _execute(self):
#         if self.running:
#             self.func(*self.args, **self.kwargs)
#             self.loop.call_later(self.interval, self._execute)
# 
#     def stop(self):
#         self.running = False
# 
# class InheritDocstrings(type):
#     def __new__(cls, cls_name, bases, classdict):
#         for attr_name, attr in classdict.items():
#             if getattr(attr, '__doc__') is None:
#                 # See if this attribute came from any of our ancestors
#                 for base in bases:
#                     if attr_name in base.__dict__:
#                         attr.__doc__ = base.__dict__[attr_name].__doc__
#                         break
#         return super().__new__(cls, cls_name, bases, classdict)


import asyncio
from unittest import TestCase
from jcn.util import (
    clamp, weighted_round_robin, crop_or_expand, LoopingCall,
    InheritDocstrings)
        self.assertEqual(
            crop_or_expand([1, 2, 3, 4, 5, 6], 2, scheme='middle'),
            [3, 4])
        self.assertEqual(crop_or_expand('abcdef', 2, scheme='middle'), 'cd')
        self.assertEqual(crop_or_expand('abcdef', 3, scheme='middle'), 'bcd')
        self.assertEqual(crop_or_expand('abcdefg', 3, scheme='middle'), 'cde')
        self.assertEqual(crop_or_expand('abcdefg', 2, scheme='middle'), 'cd')

    def test_crop_or_expand_expand(self):
        with self.assertRaises(TypeError):
            crop_or_expand([1, 2, 3], 4, default='bad')
        self.assertEqual(
            crop_or_expand([1, 2, 3], 4, default=['']),
            [1, 2, 3, ''])
        self.assertEqual(crop_or_expand('abc', 4), 'abc ')
        self.assertEqual(
            crop_or_expand([], 3, default=['moo']),
            ['moo', 'moo', 'moo'])
        self.assertEqual(crop_or_expand('', 2, default='baa'), 'baabaa')
        self.assertEqual(
            crop_or_expand([1], 5, scheme='end', default=['']),
            ['', '', '', '', 1])
        self.assertEqual(crop_or_expand('a', 6, scheme='end'), '     a')
        self.assertEqual(
            crop_or_expand([2], 5, default=[''], scheme='middle'),
            ['', '', 2, '', ''])
        self.assertEqual(
            crop_or_expand('z', 7, scheme='middle'),
            '   z   ')
        self.assertEqual(

# Path: jcn/util.py
# def clamp(value, min_=None, max_=None):
#     if min_ is None and max_ is None:
#         return value
#     if min_ is None:
#         min_ = min(value, max_)
#     if max_ is None:
#         max_ = max(value, min_)
#     return sorted((value, min_, max_))[1]
# 
# def weighted_round_robin(iterable):
#     '''Takes an iterable of tuples of <item>, <weight> and cycles around them,
#     returning heavier (integer) weighted items more frequently.
#     '''
#     cyclable_list = []
#     assigned_weight = 0
#     still_to_process = [
#         (item, weight) for item, weight in
#         sorted(iterable, key=lambda tup: tup[1], reverse=True)]
#     while still_to_process:
#         for i, (item, weight) in enumerate(still_to_process):
#             if weight > assigned_weight:
#                 cyclable_list.append(item)
#             else:
#                 del still_to_process[i]
#         assigned_weight += 1
#     return cycle(cyclable_list)
# 
# def crop_or_expand(iterable, length, default=' ', scheme='beginning'):
#     if len(iterable) > length:
#         # Crop:
#         if scheme == 'beginning':
#             result = iterable[:length]
#         elif scheme == 'middle':
#             extra = len(iterable) - length
#             result = iterable[extra // 2:-extra // 2]
#         elif scheme == 'end':
#             result = iterable[-length:]
#     elif len(iterable) < length:
#         # Expand:
#         missing = length - len(iterable)
#         try:
#             if scheme == 'beginning':
#                 result = iterable + default * missing
#             elif scheme == 'middle':
#                 result = (default * ((missing + 1) // 2) +
#                           iterable +
#                           default * (missing // 2))
#             elif scheme == 'end':
#                 result = default * missing + iterable
#         except TypeError:
#             raise TypeError(
#                 "Can't expand the given iterable of type {!r} with default "
#                 "value of type {!r}".format(type(iterable), type(default)))
#     else:
#         # Perfect :-)
#         result = iterable[:]
#     return result
# 
# class LoopingCall:
#     def __init__(self, func, *args, **kwargs):
#         self.func = func
#         self.args = args
#         self.kwargs = kwargs
#         self.interval = None
#         self.loop = None
#         self.running = False
# 
#     def start(self, interval, loop=None):
#         self.interval = interval
#         self.loop = loop or asyncio.get_event_loop()
#         self.running = True
#         self._execute()
# 
#     def _execute(self):
#         if self.running:
#             self.func(*self.args, **self.kwargs)
#             self.loop.call_later(self.interval, self._execute)
# 
#     def stop(self):
#         self.running = False
# 
# class InheritDocstrings(type):
#     def __new__(cls, cls_name, bases, classdict):
#         for attr_name, attr in classdict.items():
#             if getattr(attr, '__doc__') is None:
#                 # See if this attribute came from any of our ancestors
#                 for base in bases:
#                     if attr_name in base.__dict__:
#                         attr.__doc__ = base.__dict__[attr_name].__doc__
#                         break
#         return super().__new__(cls, cls_name, bases, classdict)


# Path: test/test_util.py
import asyncio
from unittest import TestCase
from jcn.util import (
    clamp, weighted_round_robin, crop_or_expand, LoopingCall,
    InheritDocstrings)

        self.assertEqual(
            crop_or_expand([1, 2, 3, 4, 5, 6], 2, scheme='middle'),
            [3, 4])
        self.assertEqual(crop_or_expand('abcdef', 2, scheme='middle'), 'cd')
        self.assertEqual(crop_or_expand('abcdef', 3, scheme='middle'), 'bcd')
        self.assertEqual(crop_or_expand('abcdefg', 3, scheme='middle'), 'cde')
        self.assertEqual(crop_or_expand('abcdefg', 2, scheme='middle'), 'cd')

    def test_crop_or_expand_expand(self):
        with self.assertRaises(TypeError):
            crop_or_expand([1, 2, 3], 4, default='bad')
        self.assertEqual(
            crop_or_expand([1, 2, 3], 4, default=['']),
            [1, 2, 3, ''])
        self.assertEqual(crop_or_expand('abc', 4), 'abc ')
        self.assertEqual(
            crop_or_expand([], 3, default=['moo']),
            ['moo', 'moo', 'moo'])
        self.assertEqual(crop_or_expand('', 2, default='baa'), 'baabaa')
        self.assertEqual(
            crop_or_expand([1], 5, scheme='end', default=['']),
            ['', '', '', '', 1])
        self.assertEqual(crop_or_expand('a', 6, scheme='end'), '     a')
        self.assertEqual(
            crop_or_expand([2], 5, default=[''], scheme='middle'),
            ['', '', 2, '', ''])
        self.assertEqual(
            crop_or_expand('z', 7, scheme='middle'),
            '   z   ')
        self.assertEqual(

            crop_or_expand([3], 4, default=[''], scheme='middle'),