import bisect

# === bisect_left ===
a = [1, 3, 5, 7, 9]
assert bisect.bisect_left(a, 5) == 2, 'bisect_left existing'
assert bisect.bisect_left(a, 4) == 2, 'bisect_left between'
assert bisect.bisect_left(a, 0) == 0, 'bisect_left before all'
assert bisect.bisect_left(a, 10) == 5, 'bisect_left after all'

# === bisect_right ===
assert bisect.bisect_right(a, 5) == 3, 'bisect_right existing'
assert bisect.bisect_right(a, 4) == 2, 'bisect_right between'
assert bisect.bisect_right(a, 0) == 0, 'bisect_right before all'
assert bisect.bisect_right(a, 10) == 5, 'bisect_right after all'

# === bisect is alias for bisect_right ===
assert bisect.bisect(a, 5) == 3, 'bisect alias'

# === bisect_left with duplicates ===
b = [1, 3, 3, 3, 5]
assert bisect.bisect_left(b, 3) == 1, 'bisect_left duplicates'
assert bisect.bisect_right(b, 3) == 4, 'bisect_right duplicates'

# === insort_left ===
c = [1, 3, 5, 7]
bisect.insort_left(c, 4)
assert c == [1, 3, 4, 5, 7], 'insort_left'

# === insort_right ===
d = [1, 3, 5, 7]
bisect.insort_right(d, 5)
assert d == [1, 3, 5, 5, 7], 'insort_right'

# === insort is alias for insort_right ===
e = [1, 3, 5]
bisect.insort(e, 3)
assert e == [1, 3, 3, 5], 'insort alias'

# === empty list ===
f = []
assert bisect.bisect_left(f, 1) == 0, 'bisect_left empty'
bisect.insort(f, 5)
assert f == [5], 'insort into empty'

# === lo/hi parameters for bisect_left ===
g = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
assert bisect.bisect_left(g, 5, 3, 8) == 4, 'bisect_left with lo and hi'
assert bisect.bisect_left(g, 5, 5) == 5, 'bisect_left with lo only'
assert bisect.bisect_left(g, 1, 0, 5) == 0, 'bisect_left lo=0 hi=5'

# === lo/hi parameters for bisect_right ===
assert bisect.bisect_right(g, 5, 3, 8) == 5, 'bisect_right with lo and hi'
assert bisect.bisect_right(g, 5, 5) == 5, 'bisect_right with lo only'

# === lo/hi parameters for insort_left ===
h = [1, 3, 5, 7, 9]
bisect.insort_left(h, 4, 1, 3)
assert h == [1, 3, 4, 5, 7, 9], 'insort_left with lo and hi'

# === lo/hi parameters for insort_right ===
j = [1, 3, 5, 7, 9]
bisect.insort_right(j, 6, 2, 4)
assert j == [1, 3, 5, 6, 7, 9], 'insort_right with lo and hi'

# === lo parameter only ===
k = [10, 20, 30, 40, 50]
assert bisect.bisect_left(k, 25, 2) == 2, 'bisect_left lo=2 searches from index 2'
assert bisect.bisect_right(k, 30, 2) == 3, 'bisect_right lo=2'

# === from import ===
from bisect import bisect_left, insort

m = [10, 20, 30]
assert bisect_left(m, 20) == 1, 'from import bisect_left'
insort(m, 25)
assert m == [10, 20, 25, 30], 'from import insort'

# === key functions ===
data = ['apple', 'banana', 'cherry']
assert bisect.bisect_left(data, 'banana', key=lambda x: x.lower()) == 1, 'bisect_left lambda key'
assert bisect.bisect_right(data, 'banana', key=lambda x: x.lower()) == 2, 'bisect_right lambda key'
