/.
/usr
/usr/share
/usr/share/doc
/usr/share/doc/ncurses-term
/usr/share/doc/ncurses-term/changelog.Debian.gz
/usr/share/doc/ncurses-term/changelog.gz
/usr/share/doc/ncurses-term/copyright
/usr/share/terminfo
/usr/share/terminfo/1
/usr/share/terminfo/2
/usr/share/terminfo/3
/usr/share/terminfo/4
/usr/share/terminfo/5
/usr/share/terminfo/6
/usr/share/terminfo/7
/usr/share/terminfo/8
/usr/share/terminfo/9
/usr/share/terminfo/9/9term
/usr/share/terminfo/A
/usr/share/terminfo/E
/usr/share/terminfo/E/Eterm-256color
/usr/share/terminfo/E/Eterm-88color
/usr/share/terminfo/L
/usr/share/terminfo/M
/usr/share/terminfo/M/MtxOrb
/usr/share/terminfo/M/MtxOrb162
/usr/share/terminfo/M/MtxOrb204
/usr/share/terminfo/N
/usr/share/terminfo/P
/usr/share/terminfo/Q
/usr/share/terminfo/X
/usr/share/terminfo/a
/usr/share/terminfo/a/aaa
/usr/share/terminfo/a/aaa+dec
/usr/share/terminfo/a/aaa+rv
/usr/share/terminfo/a/aaa+unk
/usr/share/terminfo/a/aaa-18
/usr/share/terminfo/a/aaa-18-rv
/usr/share/terminfo/a/aaa-20
/usr/share/terminfo/a/aaa-22
/usr/share/terminfo/a/aaa-24
/usr/share/terminfo/a/aaa-24-rv
/usr/share/terminfo/a/aaa-26
/usr/share/terminfo/a/aaa-28
/usr/share/terminfo/a/aaa-30-ctxt
/usr/share/terminfo/a/aaa-30-rv
/usr/share/terminfo/a/aaa-30-rv-ctxt
/usr/share/terminfo/a/aaa-30-s
/usr/share/terminfo/a/aaa-30-s-rv
/usr/share/terminfo/a/aaa-36
/usr/share/terminfo/a/aaa-36-rv
/usr/share/terminfo/a/aaa-40
/usr/share/terminfo/a/aaa-40-rv
/usr/share/terminfo/a/aaa-48
/usr/share/terminfo/a/aaa-48-rv
/usr/share/terminfo/a/aaa-60
/usr/share/terminfo/a/aaa-60-dec-rv
/usr/share/terminfo/a/aaa-60-rv
/usr/share/terminfo/a/aaa-60-s
/usr/share/terminfo/a/aaa-60-s-rv
/usr/share/terminfo/a/aaa-db
/usr/share/terminfo/a/aaa-rv-unk
/usr/share/terminfo/a/aaa-s-ctxt
/usr/share/terminfo/a/aaa-s-rv-ctxt
/usr/share/terminfo/a/aas1901
/usr/share/terminfo/a/abm80
/usr/share/terminfo/a/abm85
/usr/share/terminfo/a/abm85e
/usr/share/terminfo/a/abm85h
/usr/share/terminfo/a/abm85h-old
/usr/share/terminfo/a/absolute
/usr/share/terminfo/a/act4
/usr/share/terminfo/a/act5
/usr/share/terminfo/a/addrinfo
/usr/share/terminfo/a/adds980
/usr/share/terminfo/a/adm+sgr
/usr/share/terminfo/a/adm11
/usr/share/terminfo/a/adm1178
/usr/share/terminfo/a/adm12
/usr/share/terminfo/a/adm1a
/usr/share/terminfo/a/adm2
/usr/share/terminfo/a/adm20
/usr/share/terminfo/a/adm21
/usr/share/terminfo/a/adm22
/usr/share/terminfo/a/adm3
/usr/share/terminfo/a/adm31
/usr/share/terminfo/a/adm31-old
/usr/share/terminfo/a/adm36
/usr/share/terminfo/a/adm3a
/usr/share/terminfo/a/adm3a+
/usr/share/terminfo/a/adm42
/usr/share/terminfo/a/adm42-ns
/usr/share/terminfo/a/adm5
/usr/share/terminfo/a/aepro
/usr/share/terminfo/a/aixterm
/usr/share/terminfo/a/aixterm+sl
/usr/share/terminfo/a/aixterm-16color
/usr/share/terminfo/a/aixterm-m
/usr/share/terminfo/a/aixterm-m-old
/usr/share/terminfo/a/aj510
/usr/share/terminfo/a/aj830
/usr/share/terminfo/a/alacritty
/usr/share/terminfo/a/alacritty+common
/usr/share/terminfo/a/alacritty-direct
/usr/share/terminfo/a/alto-h19
/usr/share/terminfo/a/altos2
/usr/share/terminfo/a/altos3
/usr/share/terminfo/a/altos4
/usr/share/terminfo/a/altos7
/usr/share/terminfo/a/altos7pc
/usr/share/terminfo/a/amiga
/usr/share/terminfo/a/amiga-8bit
/usr/share/terminfo/a/amiga-h
/usr/share/terminfo/a/amiga-vnc
/usr/share/terminfo/a/ampex175
/usr/share/terminfo/a/ampex175-b
/usr/share/terminfo/a/ampex210
/usr/share/terminfo/a/ampex219
/usr/share/terminfo/a/ampex219w
/usr/share/terminfo/a/ampex232
/usr/share/terminfo/a/ampex232w
/usr/share/terminfo/a/ampex80
/usr/share/terminfo/a/annarbor4080
/usr/share/terminfo/a/ansi+arrows
/usr/share/terminfo/a/ansi+cpr
/usr/share/terminfo/a/ansi+csr
/usr/share/terminfo/a/ansi+cup
/usr/share/terminfo/a/ansi+enq
/usr/share/terminfo/a/ansi+erase
/usr/share/terminfo/a/ansi+idc
/usr/share/terminfo/a/ansi+idc1
/usr/share/terminfo/a/ansi+idl
/usr/share/terminfo/a/ansi+idl1
/usr/share/terminfo/a/ansi+inittabs
/usr/share/terminfo/a/ansi+local
/usr/share/terminfo/a/ansi+local1
/usr/share/terminfo/a/ansi+pp
/usr/share/terminfo/a/ansi+rca
/usr/share/terminfo/a/ansi+rca2
/usr/share/terminfo/a/ansi+rep
/usr/share/terminfo/a/ansi+sgr
/usr/share/terminfo/a/ansi+sgrbold
/usr/share/terminfo/a/ansi+sgrdim
/usr/share/terminfo/a/ansi+sgrso
/usr/share/terminfo/a/ansi+sgrul
/usr/share/terminfo/a/ansi+tabs
/usr/share/terminfo/a/ansi-color-2-emx
/usr/share/terminfo/a/ansi-color-3-emx
/usr/share/terminfo/a/ansi-emx
/usr/share/terminfo/a/ansi-generic
/usr/share/terminfo/a/ansi-m
/usr/share/terminfo/a/ansi-mini
/usr/share/terminfo/a/ansi-mr
/usr/share/terminfo/a/ansi-mtabs
/usr/share/terminfo/a/ansi-nt
/usr/share/terminfo/a/ansi.sys
/usr/share/terminfo/a/ansi.sys-old
/usr/share/terminfo/a/ansi.sysk
/usr/share/terminfo/a/ansi77
/usr/share/terminfo/a/apollo
/usr/share/terminfo/a/apollo+vt132
/usr/share/terminfo/a/apollo_15P
/usr/share/terminfo/a/apollo_19L
/usr/share/terminfo/a/apollo_color
/usr/share/terminfo/a/apple-80
/usr/share/terminfo/a/apple-ae
/usr/share/terminfo/a/apple-soroc
/usr/share/terminfo/a/apple-uterm
/usr/share/terminfo/a/apple-uterm-vb
/usr/share/terminfo/a/apple-videx
/usr/share/terminfo/a/apple-videx2
/usr/share/terminfo/a/apple-videx3
/usr/share/terminfo/a/apple-vm80
/usr/share/terminfo/a/apple2e
/usr/share/terminfo/a/apple2e-p
/usr/share/terminfo/a/apple80p
/usr/share/terminfo/a/appleII
/usr/share/terminfo/a/appleIIgs
/usr/share/terminfo/a/arm100
/usr/share/terminfo/a/arm100-w
/usr/share/terminfo/a/atari-old
/usr/share/terminfo/a/aterm
/usr/share/terminfo/a/att2300
/usr/share/terminfo/a/att2350
/usr/share/terminfo/a/att4410
/usr/share/terminfo/a/att4410v1-w
/usr/share/terminfo/a/att4415
/usr/share/terminfo/a/att4415+nl
/usr/share/terminfo/a/att4415-nl
/usr/share/terminfo/a/att4415-rv
/usr/share/terminfo/a/att4415-rv-nl
/usr/share/terminfo/a/att4415-w
/usr/share/terminfo/a/att4415-w-nl
/usr/share/terminfo/a/att4415-w-rv
/usr/share/terminfo/a/att4415-w-rv-n
/usr/share/terminfo/a/att4418
/usr/share/terminfo/a/att4418-w
/usr/share/terminfo/a/att4420
/usr/share/terminfo/a/att4424
/usr/share/terminfo/a/att4424-1
/usr/share/terminfo/a/att4424m
/usr/share/terminfo/a/att4426
/usr/share/terminfo/a/att500
/usr/share/terminfo/a/att505
/usr/share/terminfo/a/att505-22
/usr/share/terminfo/a/att505-24
/usr/share/terminfo/a/att510a
/usr/share/terminfo/a/att510d
/usr/share/terminfo/a/att5310
/usr/share/terminfo/a/att5410-w
/usr/share/terminfo/a/att5410v1
/usr/share/terminfo/a/att5420_2
/usr/share/terminfo/a/att5420_2-w
/usr/share/terminfo/a/att5425
/usr/share/terminfo/a/att5425-nl
/usr/share/terminfo/a/att5425-w
/usr/share/terminfo/a/att5620
/usr/share/terminfo/a/att5620-1
/usr/share/terminfo/a/att5620-24
/usr/share/terminfo/a/att5620-34
/usr/share/terminfo/a/att5620-s
/usr/share/terminfo/a/att605
/usr/share/terminfo/a/att605-pc
/usr/share/terminfo/a/att605-w
/usr/share/terminfo/a/att610
/usr/share/terminfo/a/att610+cvis
/usr/share/terminfo/a/att610+cvis0
/usr/share/terminfo/a/att610-103k
/usr/share/terminfo/a/att610-103k-w
/usr/share/terminfo/a/att610-w
/usr/share/terminfo/a/att615
/usr/share/terminfo/a/att615-103k
/usr/share/terminfo/a/att615-103k-w
/usr/share/terminfo/a/att615-w
/usr/share/terminfo/a/att620
/usr/share/terminfo/a/att620-103k
/usr/share/terminfo/a/att620-103k-w
/usr/share/terminfo/a/att620-w
/usr/share/terminfo/a/att630
/usr/share/terminfo/a/att630-24
/usr/share/terminfo/a/att6386
/usr/share/terminfo/a/att700
/usr/share/terminfo/a/att730
/usr/share/terminfo/a/att730-24
/usr/share/terminfo/a/att730-41
/usr/share/terminfo/a/att7300
/usr/share/terminfo/a/att730r
/usr/share/terminfo/a/att730r-24
/usr/share/terminfo/a/att730r-41
/usr/share/terminfo/a/avatar
/usr/share/terminfo/a/avatar0
/usr/share/terminfo/a/avatar0+
/usr/share/terminfo/a/avt
/usr/share/terminfo/a/avt+s
/usr/share/terminfo/a/avt-ns
/usr/share/terminfo/a/avt-rv
/usr/share/terminfo/a/avt-rv-ns
/usr/share/terminfo/a/avt-w
/usr/share/terminfo/a/avt-w-ns
/usr/share/terminfo/a/avt-w-rv
/usr/share/terminfo/a/avt-w-rv-ns
/usr/share/terminfo/a/aws
/usr/share/terminfo/a/awsc
/usr/share/terminfo/b
/usr/share/terminfo/b/bantam
/usr/share/terminfo/b/basis
/usr/share/terminfo/b/beacon
/usr/share/terminfo/b/beehive
/usr/share/terminfo/b/beehive3
/usr/share/terminfo/b/beehive4
/usr/share/terminfo/b/beterm
/usr/share/terminfo/b/bg1.25
/usr/share/terminfo/b/bg1.25nv
/usr/share/terminfo/b/bg1.25rv
/usr/share/terminfo/b/bg2.0
/usr/share/terminfo/b/bg2.0rv
/usr/share/terminfo/b/bitgraph
/usr/share/terminfo/b/blit
/usr/share/terminfo/b/bobcat
/usr/share/terminfo/b/bq300
/usr/share/terminfo/b/bq300-8
/usr/share/terminfo/b/bq300-8-pc
/usr/share/terminfo/b/bq300-8-pc-rv
/usr/share/terminfo/b/bq300-8-pc-w
/usr/share/terminfo/b/bq300-8-pc-w-rv
/usr/share/terminfo/b/bq300-8rv
/usr/share/terminfo/b/bq300-8w
/usr/share/terminfo/b/bq300-pc
/usr/share/terminfo/b/bq300-pc-rv
/usr/share/terminfo/b/bq300-pc-w
/usr/share/terminfo/b/bq300-pc-w-rv
/usr/share/terminfo/b/bq300-rv
/usr/share/terminfo/b/bq300-w
/usr/share/terminfo/b/bq300-w-8rv
/usr/share/terminfo/b/bq300-w-rv
/usr/share/terminfo/b/bracketed+paste
/usr/share/terminfo/b/bsdos-pc
/usr/share/terminfo/b/bsdos-pc-m
/usr/share/terminfo/b/bsdos-pc-nobold
/usr/share/terminfo/b/bsdos-ppc
/usr/share/terminfo/b/bsdos-sparc
/usr/share/terminfo/b/bterm
/usr/share/terminfo/c
/usr/share/terminfo/c/c100
/usr/share/terminfo/c/c100-rv
/usr/share/terminfo/c/c108
/usr/share/terminfo/c/c108-4p
/usr/share/terminfo/c/c108-rv
/usr/share/terminfo/c/c108-rv-4p
/usr/share/terminfo/c/c108-w
/usr/share/terminfo/c/ca22851
/usr/share/terminfo/c/cad68-2
/usr/share/terminfo/c/cad68-3
/usr/share/terminfo/c/cbblit
/usr/share/terminfo/c/cbunix
/usr/share/terminfo/c/cci
/usr/share/terminfo/c/cdc456
/usr/share/terminfo/c/cdc721
/usr/share/terminfo/c/cdc721-esc
/usr/share/terminfo/c/cdc721ll
/usr/share/terminfo/c/cdc752
/usr/share/terminfo/c/cdc756
/usr/share/terminfo/c/cg7900
/usr/share/terminfo/c/cit101
/usr/share/terminfo/c/cit101e
/usr/share/terminfo/c/cit101e-132
/usr/share/terminfo/c/cit101e-n
/usr/share/terminfo/c/cit101e-n132
/usr/share/terminfo/c/cit101e-rv
/usr/share/terminfo/c/cit500
/usr/share/terminfo/c/cit80
/usr/share/terminfo/c/citoh
/usr/share/terminfo/c/citoh-6lpi
/usr/share/terminfo/c/citoh-8lpi
/usr/share/terminfo/c/citoh-comp
/usr/share/terminfo/c/citoh-elite
/usr/share/terminfo/c/citoh-pica
/usr/share/terminfo/c/citoh-prop
/usr/share/terminfo/c/coco3
/usr/share/terminfo/c/color_xterm
/usr/share/terminfo/c/commodore
/usr/share/terminfo/c/cons25-m
/usr/share/terminfo/c/cons25l1
/usr/share/terminfo/c/cons25l1-m
/usr/share/terminfo/c/cons25r
/usr/share/terminfo/c/cons25r-m
/usr/share/terminfo/c/cons25w
/usr/share/terminfo/c/cons30
/usr/share/terminfo/c/cons30-m
/usr/share/terminfo/c/cons43
/usr/share/terminfo/c/cons43-m
/usr/share/terminfo/c/cons50
/usr/share/terminfo/c/cons50-m
/usr/share/terminfo/c/cons50l1
/usr/share/terminfo/c/cons50l1-m
/usr/share/terminfo/c/cons50r
/usr/share/terminfo/c/cons50r-m
/usr/share/terminfo/c/cons60
/usr/share/terminfo/c/cons60-m
/usr/share/terminfo/c/cons60l1
/usr/share/terminfo/c/cons60l1-m
/usr/share/terminfo/c/cons60r
/usr/share/terminfo/c/cons60r-m
/usr/share/terminfo/c/contel300
/usr/share/terminfo/c/contel301
/usr/share/terminfo/c/cops10
/usr/share/terminfo/c/crt
/usr/share/terminfo/c/cs10
/usr/share/terminfo/c/cs10-w
/usr/share/terminfo/c/ct8500
/usr/share/terminfo/c/ctrm
/usr/share/terminfo/c/cyb110
/usr/share/terminfo/c/cyb83
/usr/share/terminfo/c/cygwinB19
/usr/share/terminfo/c/cygwinDBG
/usr/share/terminfo/d
/usr/share/terminfo/d/d132
/usr/share/terminfo/d/d200
/usr/share/terminfo/d/d210
/usr/share/terminfo/d/d210-dg
/usr/share/terminfo/d/d211
/usr/share/terminfo/d/d211-7b
/usr/share/terminfo/d/d211-dg
/usr/share/terminfo/d/d216-dg
/usr/share/terminfo/d/d216-unix
/usr/share/terminfo/d/d216-unix-25
/usr/share/terminfo/d/d217-unix
/usr/share/terminfo/d/d217-unix-25
/usr/share/terminfo/d/d220
/usr/share/terminfo/d/d220-7b
/usr/share/terminfo/d/d220-dg
/usr/share/terminfo/d/d230c
/usr/share/terminfo/d/d230c-dg
/usr/share/terminfo/d/d400
/usr/share/terminfo/d/d410
/usr/share/terminfo/d/d410-7b
/usr/share/terminfo/d/d410-7b-w
/usr/share/terminfo/d/d410-dg
/usr/share/terminfo/d/d410-w
/usr/share/terminfo/d/d412-dg
/usr/share/terminfo/d/d412-unix
/usr/share/terminfo/d/d412-unix-25
/usr/share/terminfo/d/d412-unix-s
/usr/share/terminfo/d/d412-unix-sr
/usr/share/terminfo/d/d412-unix-w
/usr/share/terminfo/d/d413-unix
/usr/share/terminfo/d/d413-unix-25
/usr/share/terminfo/d/d413-unix-s
/usr/share/terminfo/d/d413-unix-sr
/usr/share/terminfo/d/d413-unix-w
/usr/share/terminfo/d/d414-unix
/usr/share/terminfo/d/d414-unix-25
/usr/share/terminfo/d/d414-unix-s
/usr/share/terminfo/d/d414-unix-sr
/usr/share/terminfo/d/d414-unix-w
/usr/share/terminfo/d/d430c-dg
/usr/share/terminfo/d/d430c-dg-ccc
/usr/share/terminfo/d/d430c-unix
/usr/share/terminfo/d/d430c-unix-25
/usr/share/terminfo/d/d430c-unix-25-ccc
/usr/share/terminfo/d/d430c-unix-ccc
/usr/share/terminfo/d/d430c-unix-s
/usr/share/terminfo/d/d430c-unix-s-ccc
/usr/share/terminfo/d/d430c-unix-sr
/usr/share/terminfo/d/d430c-unix-sr-ccc
/usr/share/terminfo/d/d430c-unix-w
/usr/share/terminfo/d/d430c-unix-w-ccc
/usr/share/terminfo/d/d470c
/usr/share/terminfo/d/d470c-7b
/usr/share/terminfo/d/d470c-dg
/usr/share/terminfo/d/d555
/usr/share/terminfo/d/d555-7b
/usr/share/terminfo/d/d555-7b-w
/usr/share/terminfo/d/d555-dg
/usr/share/terminfo/d/d555-w
/usr/share/terminfo/d/d577
/usr/share/terminfo/d/d577-7b
/usr/share/terminfo/d/d577-7b-w
/usr/share/terminfo/d/d577-dg
/usr/share/terminfo/d/d577-w
/usr/share/terminfo/d/d578
/usr/share/terminfo/d/d578-7b
/usr/share/terminfo/d/d800
/usr/share/terminfo/d/ddr
/usr/share/terminfo/d/dec+pp
/usr/share/terminfo/d/dec+sl
/usr/share/terminfo/d/dec-vt100
/usr/share/terminfo/d/dec-vt220
/usr/share/terminfo/d/decansi
/usr/share/terminfo/d/decid+cpr
/usr/share/terminfo/d/delta
/usr/share/terminfo/d/dg+ccc
/usr/share/terminfo/d/dg+color
/usr/share/terminfo/d/dg+color8
/usr/share/terminfo/d/dg+fixed
/usr/share/terminfo/d/dg-generic
/usr/share/terminfo/d/dg200
/usr/share/terminfo/d/dg210
/usr/share/terminfo/d/dg211
/usr/share/terminfo/d/dg450
/usr/share/terminfo/d/dg460-ansi
/usr/share/terminfo/d/dg6053
/usr/share/terminfo/d/dg6053-old
/usr/share/terminfo/d/dgkeys+11
/usr/share/terminfo/d/dgkeys+15
/usr/share/terminfo/d/dgkeys+7b
/usr/share/terminfo/d/dgkeys+8b
/usr/share/terminfo/d/dgmode+color
/usr/share/terminfo/d/dgmode+color8
/usr/share/terminfo/d/dgunix+ccc
/usr/share/terminfo/d/dgunix+fixed
/usr/share/terminfo/d/diablo1620
/usr/share/terminfo/d/diablo1620-m8
/usr/share/terminfo/d/diablo1640
/usr/share/terminfo/d/diablo1640-lm
/usr/share/terminfo/d/diablo1740-lm
/usr/share/terminfo/d/digilog
/usr/share/terminfo/d/djgpp
/usr/share/terminfo/d/djgpp203
/usr/share/terminfo/d/djgpp204
/usr/share/terminfo/d/dku7003
/usr/share/terminfo/d/dku7003-dumb
/usr/share/terminfo/d/dku7102-old
/usr/share/terminfo/d/dku7202
/usr/share/terminfo/d/dm1520
/usr/share/terminfo/d/dm2500
/usr/share/terminfo/d/dm3025
/usr/share/terminfo/d/dm3045
/usr/share/terminfo/d/dm80
/usr/share/terminfo/d/dm80w
/usr/share/terminfo/d/dmchat
/usr/share/terminfo/d/dmterm
/usr/share/terminfo/d/domterm
/usr/share/terminfo/d/dp3360
/usr/share/terminfo/d/dp8242
/usr/share/terminfo/d/dt100
/usr/share/terminfo/d/dt100w
/usr/share/terminfo/d/dt110
/usr/share/terminfo/d/dt80-sas
/usr/share/terminfo/d/dtc300s
/usr/share/terminfo/d/dtc382
/usr/share/terminfo/d/dtterm
/usr/share/terminfo/d/dumb-emacs-ansi
/usr/share/terminfo/d/dvtm
/usr/share/terminfo/d/dvtm-256color
/usr/share/terminfo/d/dw1
/usr/share/terminfo/d/dw2
/usr/share/terminfo/d/dw3
/usr/share/terminfo/d/dw4
/usr/share/terminfo/d/dwk
/usr/share/terminfo/e
/usr/share/terminfo/e/ecma+color
/usr/share/terminfo/e/ecma+index
/usr/share/terminfo/e/ecma+italics
/usr/share/terminfo/e/ecma+sgr
/usr/share/terminfo/e/ecma+strikeout
/usr/share/terminfo/e/elks
/usr/share/terminfo/e/elks-ansi
/usr/share/terminfo/e/elks-glasstty
/usr/share/terminfo/e/elks-vt52
/usr/share/terminfo/e/emu
/usr/share/terminfo/e/emu-220
/usr/share/terminfo/e/emx-base
/usr/share/terminfo/e/env230
/usr/share/terminfo/e/ep40
/usr/share/terminfo/e/ep48
/usr/share/terminfo/e/ergo4000
/usr/share/terminfo/e/esprit
/usr/share/terminfo/e/esprit-am
/usr/share/terminfo/e/eterm
/usr/share/terminfo/e/eterm-color
/usr/share/terminfo/e/ex155
/usr/share/terminfo/e/excel62
/usr/share/terminfo/e/excel62-rv
/usr/share/terminfo/e/excel62-w
/usr/share/terminfo/f
/usr/share/terminfo/f/f100
/usr/share/terminfo/f/f100-rv
/usr/share/terminfo/f/f110
/usr/share/terminfo/f/f110-14
/usr/share/terminfo/f/f110-14w
/usr/share/terminfo/f/f110-w
/usr/share/terminfo/f/f1720
/usr/share/terminfo/f/f200
/usr/share/terminfo/f/f200-w
/usr/share/terminfo/f/f200vi
/usr/share/terminfo/f/f200vi-w
/usr/share/terminfo/f/falco
/usr/share/terminfo/f/falco-p
/usr/share/terminfo/f/foot+base
/usr/share/terminfo/f/fos
/usr/share/terminfo/f/fox
/usr/share/terminfo/g
/usr/share/terminfo/g/gator
/usr/share/terminfo/g/gator-52
/usr/share/terminfo/g/gator-52t
/usr/share/terminfo/g/gator-t
/usr/share/terminfo/g/gigi
/usr/share/terminfo/g/glasstty
/usr/share/terminfo/g/gnome
/usr/share/terminfo/g/gnome+pcfkeys
/usr/share/terminfo/g/gnome-2007
/usr/share/terminfo/g/gnome-2008
/usr/share/terminfo/g/gnome-2012
/usr/share/terminfo/g/gnome-256color
/usr/share/terminfo/g/gnome-fc5
/usr/share/terminfo/g/gnome-rh62
/usr/share/terminfo/g/gnome-rh72
/usr/share/terminfo/g/gnome-rh80
/usr/share/terminfo/g/gnome-rh90
/usr/share/terminfo/g/go140
/usr/share/terminfo/g/go140w
/usr/share/terminfo/g/go225
/usr/share/terminfo/g/graphos
/usr/share/terminfo/g/graphos-30
/usr/share/terminfo/g/gs6300
/usr/share/terminfo/g/gsi
/usr/share/terminfo/g/gt40
/usr/share/terminfo/g/gt42
/usr/share/terminfo/g/guru
/usr/share/terminfo/g/guru+rv
/usr/share/terminfo/g/guru+s
/usr/share/terminfo/g/guru-24
/usr/share/terminfo/g/guru-44
/usr/share/terminfo/g/guru-44-s
/usr/share/terminfo/g/guru-76
/usr/share/terminfo/g/guru-76-lp
/usr/share/terminfo/g/guru-76-s
/usr/share/terminfo/g/guru-76-w
/usr/share/terminfo/g/guru-76-w-s
/usr/share/terminfo/g/guru-76-wm
/usr/share/terminfo/g/guru-nctxt
/usr/share/terminfo/g/guru-rv
/usr/share/terminfo/g/guru-s
/usr/share/terminfo/h
/usr/share/terminfo/h/h19
/usr/share/terminfo/h/h19-a
/usr/share/terminfo/h/h19-bs
/usr/share/terminfo/h/h19-g
/usr/share/terminfo/h/h19-u
/usr/share/terminfo/h/h19-us
/usr/share/terminfo/h/h19k
/usr/share/terminfo/h/ha8675
/usr/share/terminfo/h/ha8686
/usr/share/terminfo/h/hazel
/usr/share/terminfo/h/hds200
/usr/share/terminfo/h/hft-c
/usr/share/terminfo/h/hft-c-old
/usr/share/terminfo/h/hft-old
/usr/share/terminfo/h/hirez100
/usr/share/terminfo/h/hirez100-w
/usr/share/terminfo/h/hmod1
/usr/share/terminfo/h/hp+arrows
/usr/share/terminfo/h/hp+color
/usr/share/terminfo/h/hp+labels
/usr/share/terminfo/h/hp+pfk+arrows
/usr/share/terminfo/h/hp+pfk+cr
/usr/share/terminfo/h/hp+pfk-cr
/usr/share/terminfo/h/hp+printer
/usr/share/terminfo/h/hp110
/usr/share/terminfo/h/hp150
/usr/share/terminfo/h/hp2
/usr/share/terminfo/h/hp236
/usr/share/terminfo/h/hp2382a
/usr/share/terminfo/h/hp2392
/usr/share/terminfo/h/hp2397a
/usr/share/terminfo/h/hp2621
/usr/share/terminfo/h/hp2621-48
/usr/share/terminfo/h/hp2621-a
/usr/share/terminfo/h/hp2621-ba
/usr/share/terminfo/h/hp2621-fl
/usr/share/terminfo/h/hp2621-k45
/usr/share/terminfo/h/hp2621-nl
/usr/share/terminfo/h/hp2621-nt
/usr/share/terminfo/h/hp2621b
/usr/share/terminfo/h/hp2621b-kx
/usr/share/terminfo/h/hp2621b-kx-p
/usr/share/terminfo/h/hp2621b-p
/usr/share/terminfo/h/hp2621p
/usr/share/terminfo/h/hp2621p-a
/usr/share/terminfo/h/hp2622
/usr/share/terminfo/h/hp2623
/usr/share/terminfo/h/hp2624
/usr/share/terminfo/h/hp2624-10p
/usr/share/terminfo/h/hp2624b-10p-p
/usr/share/terminfo/h/hp2624b-p
/usr/share/terminfo/h/hp2626
/usr/share/terminfo/h/hp2626-12
/usr/share/terminfo/h/hp2626-12-s
/usr/share/terminfo/h/hp2626-12x40
/usr/share/terminfo/h/hp2626-ns
/usr/share/terminfo/h/hp2626-s
/usr/share/terminfo/h/hp2626-x40
/usr/share/terminfo/h/hp2627a
/usr/share/terminfo/h/hp2627a-rev
/usr/share/terminfo/h/hp2627c
/usr/share/terminfo/h/hp262x
/usr/share/terminfo/h/hp2640a
/usr/share/terminfo/h/hp2640b
/usr/share/terminfo/h/hp2641a
/usr/share/terminfo/h/hp2645
/usr/share/terminfo/h/hp2648
/usr/share/terminfo/h/hp300h
/usr/share/terminfo/h/hp700-wy
/usr/share/terminfo/h/hp70092
/usr/share/terminfo/h/hp9837
/usr/share/terminfo/h/hp9845
/usr/share/terminfo/h/hp98550
/usr/share/terminfo/h/hp98550-color
/usr/share/terminfo/h/hpansi
/usr/share/terminfo/h/hpex
/usr/share/terminfo/h/hpgeneric
/usr/share/terminfo/h/hpsub
/usr/share/terminfo/h/hpterm
/usr/share/terminfo/h/hpterm-color
/usr/share/terminfo/h/hpterm-color2
/usr/share/terminfo/h/hterm
/usr/share/terminfo/h/hterm-256color
/usr/share/terminfo/h/hz1000
/usr/share/terminfo/h/hz1420
/usr/share/terminfo/h/hz1500
/usr/share/terminfo/h/hz1510
/usr/share/terminfo/h/hz1520
/usr/share/terminfo/h/hz1520-noesc
/usr/share/terminfo/h/hz1552
/usr/share/terminfo/h/hz1552-rv
/usr/share/terminfo/h/hz2000
/usr/share/terminfo/i
/usr/share/terminfo/i/i100
/usr/share/terminfo/i/i400
/usr/share/terminfo/i/iTerm.app
/usr/share/terminfo/i/iTerm2.app
/usr/share/terminfo/i/ibcs2
/usr/share/terminfo/i/ibm+16color
/usr/share/terminfo/i/ibm+color
/usr/share/terminfo/i/ibm-apl
/usr/share/terminfo/i/ibm-pc
/usr/share/terminfo/i/ibm-system1
/usr/share/terminfo/i/ibm3101
/usr/share/terminfo/i/ibm3151
/usr/share/terminfo/i/ibm3161
/usr/share/terminfo/i/ibm3161-C
/usr/share/terminfo/i/ibm3162
/usr/share/terminfo/i/ibm3164
/usr/share/terminfo/i/ibm327x
/usr/share/terminfo/i/ibm5081
/usr/share/terminfo/i/ibm5081-c
/usr/share/terminfo/i/ibm5151
/usr/share/terminfo/i/ibm5154
/usr/share/terminfo/i/ibm6153
/usr/share/terminfo/i/ibm6153-40
/usr/share/terminfo/i/ibm6153-90
/usr/share/terminfo/i/ibm6154
/usr/share/terminfo/i/ibm6155
/usr/share/terminfo/i/ibm8503
/usr/share/terminfo/i/ibm8512
/usr/share/terminfo/i/ibm8514
/usr/share/terminfo/i/ibm8514-c
/usr/share/terminfo/i/ibmaed
/usr/share/terminfo/i/ibmapa8c
/usr/share/terminfo/i/ibmapa8c-c
/usr/share/terminfo/i/ibmega
/usr/share/terminfo/i/ibmega-c
/usr/share/terminfo/i/ibmmono
/usr/share/terminfo/i/ibmpc
/usr/share/terminfo/i/ibmpc3
/usr/share/terminfo/i/ibmpcx
/usr/share/terminfo/i/ibmvga
/usr/share/terminfo/i/ibmvga-c
/usr/share/terminfo/i/icl6404
/usr/share/terminfo/i/icl6404-w
/usr/share/terminfo/i/ifmr
/usr/share/terminfo/i/ims-ansi
/usr/share/terminfo/i/ims950
/usr/share/terminfo/i/ims950-b
/usr/share/terminfo/i/ims950-rv
/usr/share/terminfo/i/infoton
/usr/share/terminfo/i/infoton2
/usr/share/terminfo/i/interix
/usr/share/terminfo/i/interix-nti
/usr/share/terminfo/i/intertube
/usr/share/terminfo/i/intertube2
/usr/share/terminfo/i/intext
/usr/share/terminfo/i/intext2
/usr/share/terminfo/i/iris-ansi
/usr/share/terminfo/i/iris-ansi-ap
/usr/share/terminfo/i/iris-color
/usr/share/terminfo/i/iterm2-direct
/usr/share/terminfo/j
/usr/share/terminfo/j/jaixterm
/usr/share/terminfo/j/jaixterm-m
/usr/share/terminfo/j/jfbterm
/usr/share/terminfo/k
/usr/share/terminfo/k/kaypro
/usr/share/terminfo/k/kermit
/usr/share/terminfo/k/kermit-am
/usr/share/terminfo/k/kitty
/usr/share/terminfo/k/kitty+common
/usr/share/terminfo/k/kitty+setal
/usr/share/terminfo/k/kitty-direct
/usr/share/terminfo/k/klone+acs
/usr/share/terminfo/k/klone+color
/usr/share/terminfo/k/klone+koi8acs
/usr/share/terminfo/k/klone+sgr
/usr/share/terminfo/k/klone+sgr-dumb
/usr/share/terminfo/k/klone+sgr8
/usr/share/terminfo/k/kon
/usr/share/terminfo/k/konsole
/usr/share/terminfo/k/konsole+pcfkeys
/usr/share/terminfo/k/konsole-16color
/usr/share/terminfo/k/konsole-256color
/usr/share/terminfo/k/konsole-base
/usr/share/terminfo/k/konsole-direct
/usr/share/terminfo/k/konsole-linux
/usr/share/terminfo/k/konsole-solaris
/usr/share/terminfo/k/konsole-vt100
/usr/share/terminfo/k/konsole-vt420pc
/usr/share/terminfo/k/konsole-xf3x
/usr/share/terminfo/k/konsole-xf4x
/usr/share/terminfo/k/kt7
/usr/share/terminfo/k/kt7ix
/usr/share/terminfo/k/kterm
/usr/share/terminfo/k/kterm-color
/usr/share/terminfo/k/kvt
/usr/share/terminfo/l
/usr/share/terminfo/l/lft
/usr/share/terminfo/l/linux+decid
/usr/share/terminfo/l/linux+sfkeys
/usr/share/terminfo/l/linux-16color
/usr/share/terminfo/l/linux-basic
/usr/share/terminfo/l/linux-c
/usr/share/terminfo/l/linux-c-nc
/usr/share/terminfo/l/linux-koi8
/usr/share/terminfo/l/linux-koi8r
/usr/share/terminfo/l/linux-lat
/usr/share/terminfo/l/linux-m
/usr/share/terminfo/l/linux-m1
/usr/share/terminfo/l/linux-m1b
/usr/share/terminfo/l/linux-m2
/usr/share/terminfo/l/linux-nic
/usr/share/terminfo/l/linux-s
/usr/share/terminfo/l/linux-vt
/usr/share/terminfo/l/linux2.2
/usr/share/terminfo/l/linux2.6
/usr/share/terminfo/l/linux2.6.26
/usr/share/terminfo/l/linux3.0
/usr/share/terminfo/l/lisa
/usr/share/terminfo/l/lisaterm
/usr/share/terminfo/l/lisaterm-w
/usr/share/terminfo/l/liswb
/usr/share/terminfo/l/ln03
/usr/share/terminfo/l/ln03-w
/usr/share/terminfo/l/lpr
/usr/share/terminfo/l/luna
/usr/share/terminfo/m
/usr/share/terminfo/m/m2-nam
/usr/share/terminfo/m/mac
/usr/share/terminfo/m/mac-w
/usr/share/terminfo/m/mai
/usr/share/terminfo/m/masscomp
/usr/share/terminfo/m/masscomp1
/usr/share/terminfo/m/masscomp2
/usr/share/terminfo/m/megatek
/usr/share/terminfo/m/memhp
/usr/share/terminfo/m/mgr
/usr/share/terminfo/m/mgr-linux
/usr/share/terminfo/m/mgr-sun
/usr/share/terminfo/m/mgt
/usr/share/terminfo/m/mgterm
/usr/share/terminfo/m/microb
/usr/share/terminfo/m/mime
/usr/share/terminfo/m/mime-fb
/usr/share/terminfo/m/mime-hb
/usr/share/terminfo/m/mime2a
/usr/share/terminfo/m/mime2a-s
/usr/share/terminfo/m/mime314
/usr/share/terminfo/m/mime3a
/usr/share/terminfo/m/mime3ax
/usr/share/terminfo/m/minitel1
/usr/share/terminfo/m/minitel1-nb
/usr/share/terminfo/m/minitel12-80
/usr/share/terminfo/m/minitel1b
/usr/share/terminfo/m/minitel1b-80
/usr/share/terminfo/m/minitel1b-nb
/usr/share/terminfo/m/minitel2-80
/usr/share/terminfo/m/minix
/usr/share/terminfo/m/minix-1.7
/usr/share/terminfo/m/minix-3.0
/usr/share/terminfo/m/minix-old
/usr/share/terminfo/m/minix-old-am
/usr/share/terminfo/m/mintty
/usr/share/terminfo/m/mintty+common
/usr/share/terminfo/m/mintty-direct
/usr/share/terminfo/m/mlterm
/usr/share/terminfo/m/mlterm+pcfkeys
/usr/share/terminfo/m/mlterm-256color
/usr/share/terminfo/m/mlterm-direct
/usr/share/terminfo/m/mlterm2
/usr/share/terminfo/m/mlterm3
/usr/share/terminfo/m/mm340
/usr/share/terminfo/m/modgraph
/usr/share/terminfo/m/modgraph2
/usr/share/terminfo/m/modgraph48
/usr/share/terminfo/m/mono-emx
/usr/share/terminfo/m/morphos
/usr/share/terminfo/m/mosh
/usr/share/terminfo/m/mosh-256color
/usr/share/terminfo/m/mrxvt
/usr/share/terminfo/m/mrxvt-256color
/usr/share/terminfo/m/ms-terminal
/usr/share/terminfo/m/ms-vt-utf8
/usr/share/terminfo/m/ms-vt100
/usr/share/terminfo/m/ms-vt100+
/usr/share/terminfo/m/ms-vt100-color
/usr/share/terminfo/m/msk227
/usr/share/terminfo/m/msk22714
/usr/share/terminfo/m/msk227am
/usr/share/terminfo/m/mt4520-rv
/usr/share/terminfo/m/mt70
/usr/share/terminfo/m/mterm
/usr/share/terminfo/m/mterm-ansi
/usr/share/terminfo/m/mvterm
/usr/share/terminfo/n
/usr/share/terminfo/n/nansi.sys
/usr/share/terminfo/n/nansi.sysk
/usr/share/terminfo/n/ncr160vppp
/usr/share/terminfo/n/ncr160vpwpp
/usr/share/terminfo/n/ncr160vt100an
/usr/share/terminfo/n/ncr160vt100pp
/usr/share/terminfo/n/ncr160vt100wan
/usr/share/terminfo/n/ncr160vt100wpp
/usr/share/terminfo/n/ncr160vt200an
/usr/share/terminfo/n/ncr160vt200pp
/usr/share/terminfo/n/ncr160vt200wan
/usr/share/terminfo/n/ncr160vt200wpp
/usr/share/terminfo/n/ncr160vt300an
/usr/share/terminfo/n/ncr160vt300pp
/usr/share/terminfo/n/ncr160vt300wan
/usr/share/terminfo/n/ncr160vt300wpp
/usr/share/terminfo/n/ncr160wy50+pp
/usr/share/terminfo/n/ncr160wy50+wpp
/usr/share/terminfo/n/ncr160wy60pp
/usr/share/terminfo/n/ncr160wy60wpp
/usr/share/terminfo/n/ncr260intan
/usr/share/terminfo/n/ncr260intpp
/usr/share/terminfo/n/ncr260intwan
/usr/share/terminfo/n/ncr260intwpp
/usr/share/terminfo/n/ncr260vp+sl
/usr/share/terminfo/n/ncr260vppp
/usr/share/terminfo/n/ncr260vpwpp
/usr/share/terminfo/n/ncr260vt+sl
/usr/share/terminfo/n/ncr260vt100an
/usr/share/terminfo/n/ncr260vt100pp
/usr/share/terminfo/n/ncr260vt100wan
/usr/share/terminfo/n/ncr260vt100wpp
/usr/share/terminfo/n/ncr260vt200an
/usr/share/terminfo/n/ncr260vt200pp
/usr/share/terminfo/n/ncr260vt200wan
/usr/share/terminfo/n/ncr260vt200wpp
/usr/share/terminfo/n/ncr260vt300an
/usr/share/terminfo/n/ncr260vt300pp
/usr/share/terminfo/n/ncr260vt300wan
/usr/share/terminfo/n/ncr260vt300wpp
/usr/share/terminfo/n/ncr260wy325pp
/usr/share/terminfo/n/ncr260wy325wpp
/usr/share/terminfo/n/ncr260wy350pp
/usr/share/terminfo/n/ncr260wy350wpp
/usr/share/terminfo/n/ncr260wy50+pp
/usr/share/terminfo/n/ncr260wy50+wpp
/usr/share/terminfo/n/ncr260wy60pp
/usr/share/terminfo/n/ncr260wy60wpp
/usr/share/terminfo/n/ncr7900i
/usr/share/terminfo/n/ncr7900iv
/usr/share/terminfo/n/ncr7901
/usr/share/terminfo/n/ncrvt100an
/usr/share/terminfo/n/ncrvt100wan
/usr/share/terminfo/n/ncsa
/usr/share/terminfo/n/ncsa-m
/usr/share/terminfo/n/ncsa-m-ns
/usr/share/terminfo/n/ncsa-ns
/usr/share/terminfo/n/ncsa-vt220
/usr/share/terminfo/n/ndr9500
/usr/share/terminfo/n/ndr9500-25
/usr/share/terminfo/n/ndr9500-25-mc
/usr/share/terminfo/n/ndr9500-25-mc-nl
/usr/share/terminfo/n/ndr9500-25-nl
/usr/share/terminfo/n/ndr9500-mc
/usr/share/terminfo/n/ndr9500-mc-nl
/usr/share/terminfo/n/ndr9500-nl
/usr/share/terminfo/n/nec5520
/usr/share/terminfo/n/netbsd6
/usr/share/terminfo/n/newhp
/usr/share/terminfo/n/newhpkeyboard
/usr/share/terminfo/n/news-29
/usr/share/terminfo/n/news-29-euc
/usr/share/terminfo/n/news-29-sjis
/usr/share/terminfo/n/news-33
/usr/share/terminfo/n/news-33-euc
/usr/share/terminfo/n/news-33-sjis
/usr/share/terminfo/n/news-42
/usr/share/terminfo/n/news-42-euc
/usr/share/terminfo/n/news-42-sjis
/usr/share/terminfo/n/news-old-unk
/usr/share/terminfo/n/news-unk
/usr/share/terminfo/n/news28
/usr/share/terminfo/n/news29
/usr/share/terminfo/n/next
/usr/share/terminfo/n/nextshell
/usr/share/terminfo/n/no+brackets
/usr/share/terminfo/n/northstar
/usr/share/terminfo/n/nsterm
/usr/share/terminfo/n/nsterm+7
/usr/share/terminfo/n/nsterm+acs
/usr/share/terminfo/n/nsterm+c
/usr/share/terminfo/n/nsterm+c41
/usr/share/terminfo/n/nsterm+mac
/usr/share/terminfo/n/nsterm+s
/usr/share/terminfo/n/nsterm-16color
/usr/share/terminfo/n/nsterm-7
/usr/share/terminfo/n/nsterm-7-c
/usr/share/terminfo/n/nsterm-acs
/usr/share/terminfo/n/nsterm-bce
/usr/share/terminfo/n/nsterm-build309
/usr/share/terminfo/n/nsterm-build326
/usr/share/terminfo/n/nsterm-build343
/usr/share/terminfo/n/nsterm-build361
/usr/share/terminfo/n/nsterm-build400
/usr/share/terminfo/n/nsterm-build440
/usr/share/terminfo/n/nsterm-c
/usr/share/terminfo/n/nsterm-c-acs
/usr/share/terminfo/n/nsterm-c-s
/usr/share/terminfo/n/nsterm-c-s-7
/usr/share/terminfo/n/nsterm-c-s-acs
/usr/share/terminfo/n/nsterm-direct
/usr/share/terminfo/n/nsterm-m
/usr/share/terminfo/n/nsterm-m-7
/usr/share/terminfo/n/nsterm-m-acs
/usr/share/terminfo/n/nsterm-m-s
/usr/share/terminfo/n/nsterm-m-s-7
/usr/share/terminfo/n/nsterm-m-s-acs
/usr/share/terminfo/n/nsterm-old
/usr/share/terminfo/n/nsterm-s
/usr/share/terminfo/n/nsterm-s-7
/usr/share/terminfo/n/nsterm-s-acs
/usr/share/terminfo/n/nwp511
/usr/share/terminfo/n/nwp512
/usr/share/terminfo/n/nwp512-a
/usr/share/terminfo/n/nwp513
/usr/share/terminfo/n/nwp513-a
/usr/share/terminfo/n/nwp517
/usr/share/terminfo/n/nwp517-w
/usr/share/terminfo/o
/usr/share/terminfo/o/oblit
/usr/share/terminfo/o/oc100
/usr/share/terminfo/o/ofcons
/usr/share/terminfo/o/oldpc3
/usr/share/terminfo/o/oldsun
/usr/share/terminfo/o/omron
/usr/share/terminfo/o/opennt-100
/usr/share/terminfo/o/opennt-100-nti
/usr/share/terminfo/o/opennt-35
/usr/share/terminfo/o/opennt-35-nti
/usr/share/terminfo/o/opennt-35-w
/usr/share/terminfo/o/opennt-50
/usr/share/terminfo/o/opennt-50-nti
/usr/share/terminfo/o/opennt-50-w
/usr/share/terminfo/o/opennt-60
/usr/share/terminfo/o/opennt-60-nti
/usr/share/terminfo/o/opennt-60-w
/usr/share/terminfo/o/opennt-w
/usr/share/terminfo/o/opennt-w-vt
/usr/share/terminfo/o/opus3n1+
/usr/share/terminfo/o/origpc3
/usr/share/terminfo/o/osborne
/usr/share/terminfo/o/osborne-w
/usr/share/terminfo/o/osexec
/usr/share/terminfo/o/otek4112
/usr/share/terminfo/o/otek4115
/usr/share/terminfo/o/owl
/usr/share/terminfo/p
/usr/share/terminfo/p/p19
/usr/share/terminfo/p/p8gl
/usr/share/terminfo/p/pc-coherent
/usr/share/terminfo/p/pc-minix
/usr/share/terminfo/p/pc-venix
/usr/share/terminfo/p/pc3
/usr/share/terminfo/p/pc6300plus
/usr/share/terminfo/p/pcansi-25
/usr/share/terminfo/p/pcansi-25-m
/usr/share/terminfo/p/pcansi-33
/usr/share/terminfo/p/pcansi-33-m
/usr/share/terminfo/p/pcansi-43
/usr/share/terminfo/p/pcansi-43-m
/usr/share/terminfo/p/pcansi-m
/usr/share/terminfo/p/pccon
/usr/share/terminfo/p/pccon+base
/usr/share/terminfo/p/pccon+colors
/usr/share/terminfo/p/pccon+keys
/usr/share/terminfo/p/pccon+sgr+acs
/usr/share/terminfo/p/pccon+sgr+acs0
/usr/share/terminfo/p/pccon-m
/usr/share/terminfo/p/pccon0
/usr/share/terminfo/p/pccon0-m
/usr/share/terminfo/p/pccons
/usr/share/terminfo/p/pcix
/usr/share/terminfo/p/pckermit
/usr/share/terminfo/p/pckermit120
/usr/share/terminfo/p/pcmw
/usr/share/terminfo/p/pcplot
/usr/share/terminfo/p/pcvt25
/usr/share/terminfo/p/pcvt25-color
/usr/share/terminfo/p/pcvt25w
/usr/share/terminfo/p/pcvt28
/usr/share/terminfo/p/pcvt28w
/usr/share/terminfo/p/pcvt35
/usr/share/terminfo/p/pcvt35w
/usr/share/terminfo/p/pcvt40
/usr/share/terminfo/p/pcvt40w
/usr/share/terminfo/p/pcvt43
/usr/share/terminfo/p/pcvt43w
/usr/share/terminfo/p/pcvt50
/usr/share/terminfo/p/pcvt50w
/usr/share/terminfo/p/pcvtXX
/usr/share/terminfo/p/pe1251
/usr/share/terminfo/p/pe7000c
/usr/share/terminfo/p/pe7000m
/usr/share/terminfo/p/pilot
/usr/share/terminfo/p/pmcons
/usr/share/terminfo/p/prism12
/usr/share/terminfo/p/prism12-m
/usr/share/terminfo/p/prism12-m-w
/usr/share/terminfo/p/prism12-w
/usr/share/terminfo/p/prism14
/usr/share/terminfo/p/prism14-m
/usr/share/terminfo/p/prism14-m-w
/usr/share/terminfo/p/prism14-w
/usr/share/terminfo/p/prism2
/usr/share/terminfo/p/prism4
/usr/share/terminfo/p/prism5
/usr/share/terminfo/p/prism7
/usr/share/terminfo/p/prism8
/usr/share/terminfo/p/prism8-w
/usr/share/terminfo/p/prism9
/usr/share/terminfo/p/prism9-8
/usr/share/terminfo/p/prism9-8-w
/usr/share/terminfo/p/prism9-w
/usr/share/terminfo/p/pro350
/usr/share/terminfo/p/ps300
/usr/share/terminfo/p/psterm
/usr/share/terminfo/p/psterm-80x24
/usr/share/terminfo/p/psterm-90x28
/usr/share/terminfo/p/psterm-96x48
/usr/share/terminfo/p/psterm-fast
/usr/share/terminfo/p/pt100
/usr/share/terminfo/p/pt100w
/usr/share/terminfo/p/pt210
/usr/share/terminfo/p/pt250
/usr/share/terminfo/p/pt250w
/usr/share/terminfo/p/pty
/usr/share/terminfo/p/putty
/usr/share/terminfo/p/putty+fnkeys
/usr/share/terminfo/p/putty+fnkeys+esc
/usr/share/terminfo/p/putty+fnkeys+linux
/usr/share/terminfo/p/putty+fnkeys+sco
/usr/share/terminfo/p/putty+fnkeys+vt100
/usr/share/terminfo/p/putty+fnkeys+vt400
/usr/share/terminfo/p/putty+fnkeys+xterm
/usr/share/terminfo/p/putty+keypad
/usr/share/terminfo/p/putty+screen
/usr/share/terminfo/p/putty-256color
/usr/share/terminfo/p/putty-m1
/usr/share/terminfo/p/putty-m1b
/usr/share/terminfo/p/putty-m2
/usr/share/terminfo/p/putty-noapp
/usr/share/terminfo/p/putty-sco
/usr/share/terminfo/p/putty-screen
/usr/share/terminfo/p/putty-vt100
/usr/share/terminfo/q
/usr/share/terminfo/q/qansi
/usr/share/terminfo/q/qansi-g
/usr/share/terminfo/q/qansi-m
/usr/share/terminfo/q/qansi-t
/usr/share/terminfo/q/qansi-w
/usr/share/terminfo/q/qdss
/usr/share/terminfo/q/qnx
/usr/share/terminfo/q/qnxm
/usr/share/terminfo/q/qnxt
/usr/share/terminfo/q/qnxt2
/usr/share/terminfo/q/qnxtmono
/usr/share/terminfo/q/qnxw
/usr/share/terminfo/q/qume5
/usr/share/terminfo/q/qvt101
/usr/share/terminfo/q/qvt101+
/usr/share/terminfo/q/qvt102
/usr/share/terminfo/q/qvt103
/usr/share/terminfo/q/qvt103-w
/usr/share/terminfo/q/qvt119+
/usr/share/terminfo/q/qvt119+-25
/usr/share/terminfo/q/qvt119+-25-w
/usr/share/terminfo/q/qvt119+-w
/usr/share/terminfo/q/qvt203
/usr/share/terminfo/q/qvt203-25
/usr/share/terminfo/q/qvt203-25-w
/usr/share/terminfo/q/qvt203-w
/usr/share/terminfo/r
/usr/share/terminfo/r/rbcomm
/usr/share/terminfo/r/rbcomm-nam
/usr/share/terminfo/r/rbcomm-w
/usr/share/terminfo/r/rca
/usr/share/terminfo/r/rcons
/usr/share/terminfo/r/rcons-color
/usr/share/terminfo/r/regent
/usr/share/terminfo/r/regent100
/usr/share/terminfo/r/regent20
/usr/share/terminfo/r/regent25
/usr/share/terminfo/r/regent40
/usr/share/terminfo/r/regent40+
/usr/share/terminfo/r/regent60
/usr/share/terminfo/r/rt6221
/usr/share/terminfo/r/rt6221-w
/usr/share/terminfo/r/rtpc
/usr/share/terminfo/r/rxvt+pcfkeys
/usr/share/terminfo/r/rxvt-16color
/usr/share/terminfo/r/rxvt-256color
/usr/share/terminfo/r/rxvt-88color
/usr/share/terminfo/r/rxvt-cygwin
/usr/share/terminfo/r/rxvt-cygwin-native
/usr/share/terminfo/r/rxvt-xpm
/usr/share/terminfo/s
/usr/share/terminfo/s/sb1
/usr/share/terminfo/s/sb2
/usr/share/terminfo/s/sbi
/usr/share/terminfo/s/scanset
/usr/share/terminfo/s/scoansi
/usr/share/terminfo/s/scoansi-new
/usr/share/terminfo/s/scoansi-old
/usr/share/terminfo/s/screen+fkeys
/usr/share/terminfo/s/screen+italics
/usr/share/terminfo/s/screen-16color
/usr/share/terminfo/s/screen-16color-bce
/usr/share/terminfo/s/screen-16color-bce-s
/usr/share/terminfo/s/screen-16color-s
/usr/share/terminfo/s/screen-256color-bce-s
/usr/share/terminfo/s/screen-256color-s
/usr/share/terminfo/s/screen-base
/usr/share/terminfo/s/screen-bce.Eterm
/usr/share/terminfo/s/screen-bce.gnome
/usr/share/terminfo/s/screen-bce.konsole
/usr/share/terminfo/s/screen-bce.linux
/usr/share/terminfo/s/screen-bce.mrxvt
/usr/share/terminfo/s/screen-bce.rxvt
/usr/share/terminfo/s/screen-bce.xterm-new
/usr/share/terminfo/s/screen.Eterm
/usr/share/terminfo/s/screen.gnome
/usr/share/terminfo/s/screen.konsole
/usr/share/terminfo/s/screen.konsole-256color
/usr/share/terminfo/s/screen.linux
/usr/share/terminfo/s/screen.linux-m1
/usr/share/terminfo/s/screen.linux-m1b
/usr/share/terminfo/s/screen.linux-m2
/usr/share/terminfo/s/screen.minitel1
/usr/share/terminfo/s/screen.minitel1-nb
/usr/share/terminfo/s/screen.minitel1b
/usr/share/terminfo/s/screen.minitel1b-80
/usr/share/terminfo/s/screen.minitel1b-nb
/usr/share/terminfo/s/screen.mlterm
/usr/share/terminfo/s/screen.mlterm-256color
/usr/share/terminfo/s/screen.mrxvt
/usr/share/terminfo/s/screen.putty
/usr/share/terminfo/s/screen.putty-256color
/usr/share/terminfo/s/screen.putty-m1
/usr/share/terminfo/s/screen.putty-m1b
/usr/share/terminfo/s/screen.putty-m2
/usr/share/terminfo/s/screen.rxvt
/usr/share/terminfo/s/screen.teraterm
/usr/share/terminfo/s/screen.vte
/usr/share/terminfo/s/screen.vte-256color
/usr/share/terminfo/s/screen.xterm-r6
/usr/share/terminfo/s/screen.xterm-xfree86
/usr/share/terminfo/s/screen2
/usr/share/terminfo/s/screen3
/usr/share/terminfo/s/screen4
/usr/share/terminfo/s/screen5
/usr/share/terminfo/s/screwpoint
/usr/share/terminfo/s/scrhp
/usr/share/terminfo/s/scrt
/usr/share/terminfo/s/sibo
/usr/share/terminfo/s/simpleterm
/usr/share/terminfo/s/simterm
/usr/share/terminfo/s/soroc120
/usr/share/terminfo/s/soroc140
/usr/share/terminfo/s/st
/usr/share/terminfo/s/st-0.6
/usr/share/terminfo/s/st-0.7
/usr/share/terminfo/s/st-0.8
/usr/share/terminfo/s/st-16color
/usr/share/terminfo/s/st-256color
/usr/share/terminfo/s/st-direct
/usr/share/terminfo/s/st52
/usr/share/terminfo/s/st52-color
/usr/share/terminfo/s/st52-old
/usr/share/terminfo/s/stv52
/usr/share/terminfo/s/stv52pc
/usr/share/terminfo/s/sun+sl
/usr/share/terminfo/s/sun-1
/usr/share/terminfo/s/sun-12
/usr/share/terminfo/s/sun-17
/usr/share/terminfo/s/sun-24
/usr/share/terminfo/s/sun-34
/usr/share/terminfo/s/sun-48
/usr/share/terminfo/s/sun-c
/usr/share/terminfo/s/sun-cgsix
/usr/share/terminfo/s/sun-color
/usr/share/terminfo/s/sun-e
/usr/share/terminfo/s/sun-e-s
/usr/share/terminfo/s/sun-il
/usr/share/terminfo/s/sun-s
/usr/share/terminfo/s/sun-type4
/usr/share/terminfo/s/superbee-xsb
/usr/share/terminfo/s/superbeeic
/usr/share/terminfo/s/superbrain
/usr/share/terminfo/s/swtp
/usr/share/terminfo/s/synertek
/usr/share/terminfo/t
/usr/share/terminfo/t/t10
/usr/share/terminfo/t/t1061
/usr/share/terminfo/t/t1061f
/usr/share/terminfo/t/t16
/usr/share/terminfo/t/t3700
/usr/share/terminfo/t/t3800
/usr/share/terminfo/t/tab132
/usr/share/terminfo/t/tab132-rv
/usr/share/terminfo/t/tab132-w
/usr/share/terminfo/t/tab132-w-rv
/usr/share/terminfo/t/tandem6510
/usr/share/terminfo/t/tandem653
/usr/share/terminfo/t/tek
/usr/share/terminfo/t/tek4013
/usr/share/terminfo/t/tek4014
/usr/share/terminfo/t/tek4014-sm
/usr/share/terminfo/t/tek4015
/usr/share/terminfo/t/tek4015-sm
/usr/share/terminfo/t/tek4023
/usr/share/terminfo/t/tek4024
/usr/share/terminfo/t/tek4025-17
/usr/share/terminfo/t/tek4025-17-ws
/usr/share/terminfo/t/tek4025-cr
/usr/share/terminfo/t/tek4025-ex
/usr/share/terminfo/t/tek4025a
/usr/share/terminfo/t/tek4025ex
/usr/share/terminfo/t/tek4105
/usr/share/terminfo/t/tek4105-30
/usr/share/terminfo/t/tek4105a
/usr/share/terminfo/t/tek4106brl
/usr/share/terminfo/t/tek4107
/usr/share/terminfo/t/tek4112
/usr/share/terminfo/t/tek4112-5
/usr/share/terminfo/t/tek4112-nd
/usr/share/terminfo/t/tek4113
/usr/share/terminfo/t/tek4113-34
/usr/share/terminfo/t/tek4113-nd
/usr/share/terminfo/t/tek4115
/usr/share/terminfo/t/tek4125
/usr/share/terminfo/t/tek4205
/usr/share/terminfo/t/tek4207
/usr/share/terminfo/t/tek4207-s
/usr/share/terminfo/t/tek4404
/usr/share/terminfo/t/teken
/usr/share/terminfo/t/teken-16color
/usr/share/terminfo/t/teken-2018
/usr/share/terminfo/t/teken-2022
/usr/share/terminfo/t/teken-sc
/usr/share/terminfo/t/teken-sc+fkeys
/usr/share/terminfo/t/teken-vt+fkeys
/usr/share/terminfo/t/teletec
/usr/share/terminfo/t/teraterm
/usr/share/terminfo/t/teraterm-256color
/usr/share/terminfo/t/teraterm2.3
/usr/share/terminfo/t/teraterm4.59
/usr/share/terminfo/t/teraterm4.97
/usr/share/terminfo/t/terminator
/usr/share/terminfo/t/terminet1200
/usr/share/terminfo/t/terminology
/usr/share/terminfo/t/terminology-0.6.1
/usr/share/terminfo/t/terminology-1.0.0
/usr/share/terminfo/t/terminology-1.8.1
/usr/share/terminfo/t/termite
/usr/share/terminfo/t/ti700
/usr/share/terminfo/t/ti703
/usr/share/terminfo/t/ti703-w
/usr/share/terminfo/t/ti916
/usr/share/terminfo/t/ti916-132
/usr/share/terminfo/t/ti916-8
/usr/share/terminfo/t/ti916-8-132
/usr/share/terminfo/t/ti924
/usr/share/terminfo/t/ti924-8
/usr/share/terminfo/t/ti924-8w
/usr/share/terminfo/t/ti924w
/usr/share/terminfo/t/ti926
/usr/share/terminfo/t/ti926-8
/usr/share/terminfo/t/ti928
/usr/share/terminfo/t/ti928-8
/usr/share/terminfo/t/ti931
/usr/share/terminfo/t/ti_ansi
/usr/share/terminfo/t/tmux-direct
/usr/share/terminfo/t/trs16
/usr/share/terminfo/t/trs2
/usr/share/terminfo/t/ts100
/usr/share/terminfo/t/ts100-ctxt
/usr/share/terminfo/t/tt
/usr/share/terminfo/t/tt52
/usr/share/terminfo/t/tty33
/usr/share/terminfo/t/tty37
/usr/share/terminfo/t/tty40
/usr/share/terminfo/t/tty43
/usr/share/terminfo/t/tvi803
/usr/share/terminfo/t/tvi9065
/usr/share/terminfo/t/tvi910
/usr/share/terminfo/t/tvi910+
/usr/share/terminfo/t/tvi912
/usr/share/terminfo/t/tvi912b
/usr/share/terminfo/t/tvi912b+2p
/usr/share/terminfo/t/tvi912b+dim
/usr/share/terminfo/t/tvi912b+mc
/usr/share/terminfo/t/tvi912b+printer
/usr/share/terminfo/t/tvi912b+vb
/usr/share/terminfo/t/tvi912b-2p
/usr/share/terminfo/t/tvi912b-2p-mc
/usr/share/terminfo/t/tvi912b-2p-p
/usr/share/terminfo/t/tvi912b-2p-unk
/usr/share/terminfo/t/tvi912b-mc
/usr/share/terminfo/t/tvi912b-p
/usr/share/terminfo/t/tvi912b-unk
/usr/share/terminfo/t/tvi912b-vb
/usr/share/terminfo/t/tvi912b-vb-mc
/usr/share/terminfo/t/tvi912b-vb-p
/usr/share/terminfo/t/tvi912b-vb-unk
/usr/share/terminfo/t/tvi912cc
/usr/share/terminfo/t/tvi920b
/usr/share/terminfo/t/tvi920b+fn
/usr/share/terminfo/t/tvi920b-2p
/usr/share/terminfo/t/tvi920b-2p-mc
/usr/share/terminfo/t/tvi920b-2p-p
/usr/share/terminfo/t/tvi920b-2p-unk
/usr/share/terminfo/t/tvi920b-mc
/usr/share/terminfo/t/tvi920b-p
/usr/share/terminfo/t/tvi920b-unk
/usr/share/terminfo/t/tvi920b-vb
/usr/share/terminfo/t/tvi920b-vb-mc
/usr/share/terminfo/t/tvi920b-vb-p
/usr/share/terminfo/t/tvi920b-vb-unk
/usr/share/terminfo/t/tvi921
/usr/share/terminfo/t/tvi924
/usr/share/terminfo/t/tvi925
/usr/share/terminfo/t/tvi925-hi
/usr/share/terminfo/t/tvi92B
/usr/share/terminfo/t/tvi92D
/usr/share/terminfo/t/tvi950
/usr/share/terminfo/t/tvi950-2p
/usr/share/terminfo/t/tvi950-4p
/usr/share/terminfo/t/tvi950-rv
/usr/share/terminfo/t/tvi950-rv-2p
/usr/share/terminfo/t/tvi950-rv-4p
/usr/share/terminfo/t/tvi955
/usr/share/terminfo/t/tvi955-hb
/usr/share/terminfo/t/tvi955-w
/usr/share/terminfo/t/tvi970
/usr/share/terminfo/t/tvi970-2p
/usr/share/terminfo/t/tvi970-vb
/usr/share/terminfo/t/tvipt
/usr/share/terminfo/t/tw100
/usr/share/terminfo/t/tw52
/usr/share/terminfo/t/tw52-m
/usr/share/terminfo/t/tws-generic
/usr/share/terminfo/t/tws2102-sna
/usr/share/terminfo/t/tws2103
/usr/share/terminfo/t/tws2103-sna
/usr/share/terminfo/u
/usr/share/terminfo/u/uniterm
/usr/share/terminfo/u/unknown
/usr/share/terminfo/u/uts30
/usr/share/terminfo/u/uwin
/usr/share/terminfo/v
/usr/share/terminfo/v/v3220
/usr/share/terminfo/v/v5410
/usr/share/terminfo/v/vanilla
/usr/share/terminfo/v/vc303
/usr/share/terminfo/v/vc303a
/usr/share/terminfo/v/vc404
/usr/share/terminfo/v/vc404-s
/usr/share/terminfo/v/vc414
/usr/share/terminfo/v/vc415
/usr/share/terminfo/v/versaterm
/usr/share/terminfo/v/vi200
/usr/share/terminfo/v/vi200-f
/usr/share/terminfo/v/vi200-rv
/usr/share/terminfo/v/vi300
/usr/share/terminfo/v/vi300-old
/usr/share/terminfo/v/vi50
/usr/share/terminfo/v/vi500
/usr/share/terminfo/v/vi50adm
/usr/share/terminfo/v/vi55
/usr/share/terminfo/v/vi550
/usr/share/terminfo/v/vi603
/usr/share/terminfo/v/viewdata
/usr/share/terminfo/v/viewdata-o
/usr/share/terminfo/v/viewdata-rv
/usr/share/terminfo/v/viewpoint
/usr/share/terminfo/v/vip
/usr/share/terminfo/v/vip-H
/usr/share/terminfo/v/vip-Hw
/usr/share/terminfo/v/vip-w
/usr/share/terminfo/v/visa50
/usr/share/terminfo/v/vp3a+
/usr/share/terminfo/v/vp60
/usr/share/terminfo/v/vp90
/usr/share/terminfo/v/vremote
/usr/share/terminfo/v/vsc
/usr/share/terminfo/v/vscode
/usr/share/terminfo/v/vscode-direct
/usr/share/terminfo/v/vt100+4bsd
/usr/share/terminfo/v/vt100+enq
/usr/share/terminfo/v/vt100+fnkeys
/usr/share/terminfo/v/vt100+keypad
/usr/share/terminfo/v/vt100+pfkeys
/usr/share/terminfo/v/vt100-nav
/usr/share/terminfo/v/vt100-nav-w
/usr/share/terminfo/v/vt100-putty
/usr/share/terminfo/v/vt100-s
/usr/share/terminfo/v/vt100-s-bot
/usr/share/terminfo/v/vt100-vb
/usr/share/terminfo/v/vt100-w
/usr/share/terminfo/v/vt100-w-nam
/usr/share/terminfo/v/vt100nam
/usr/share/terminfo/v/vt102+enq
/usr/share/terminfo/v/vt102-nsgr
/usr/share/terminfo/v/vt102-w
/usr/share/terminfo/v/vt125
/usr/share/terminfo/v/vt131
/usr/share/terminfo/v/vt132
/usr/share/terminfo/v/vt200-js
/usr/share/terminfo/v/vt220+cvis
/usr/share/terminfo/v/vt220+cvis8
/usr/share/terminfo/v/vt220+keypad
/usr/share/terminfo/v/vt220+pcedit
/usr/share/terminfo/v/vt220+vtedit
/usr/share/terminfo/v/vt220-8bit
/usr/share/terminfo/v/vt220-base
/usr/share/terminfo/v/vt220-nam
/usr/share/terminfo/v/vt220-old
/usr/share/terminfo/v/vt220-w
/usr/share/terminfo/v/vt220d
/usr/share/terminfo/v/vt320
/usr/share/terminfo/v/vt320-k3
/usr/share/terminfo/v/vt320-k311
/usr/share/terminfo/v/vt320-nam
/usr/share/terminfo/v/vt320-w
/usr/share/terminfo/v/vt320-w-nam
/usr/share/terminfo/v/vt320nam
/usr/share/terminfo/v/vt340
/usr/share/terminfo/v/vt400
/usr/share/terminfo/v/vt420
/usr/share/terminfo/v/vt420+lrmm
/usr/share/terminfo/v/vt420f
/usr/share/terminfo/v/vt420pc
/usr/share/terminfo/v/vt420pcdos
/usr/share/terminfo/v/vt50
/usr/share/terminfo/v/vt50h
/usr/share/terminfo/v/vt510
/usr/share/terminfo/v/vt510pc
/usr/share/terminfo/v/vt510pcdos
/usr/share/terminfo/v/vt52+keypad
/usr/share/terminfo/v/vt52-basic
/usr/share/terminfo/v/vt520
/usr/share/terminfo/v/vt520ansi
/usr/share/terminfo/v/vt525
/usr/share/terminfo/v/vt61
/usr/share/terminfo/v/vte
/usr/share/terminfo/v/vte+pcfkeys
/usr/share/terminfo/v/vte-2007
/usr/share/terminfo/v/vte-2008
/usr/share/terminfo/v/vte-2012
/usr/share/terminfo/v/vte-2014
/usr/share/terminfo/v/vte-2017
/usr/share/terminfo/v/vte-2018
/usr/share/terminfo/v/vte-256color
/usr/share/terminfo/v/vte-direct
/usr/share/terminfo/v/vwmterm
/usr/share/terminfo/w
/usr/share/terminfo/w/wsiris
/usr/share/terminfo/w/wy100
/usr/share/terminfo/w/wy100q
/usr/share/terminfo/w/wy120
/usr/share/terminfo/w/wy120-25
/usr/share/terminfo/w/wy120-25-w
/usr/share/terminfo/w/wy120-vb
/usr/share/terminfo/w/wy120-w
/usr/share/terminfo/w/wy120-w-vb
/usr/share/terminfo/w/wy160
/usr/share/terminfo/w/wy160-25
/usr/share/terminfo/w/wy160-25-w
/usr/share/terminfo/w/wy160-42
/usr/share/terminfo/w/wy160-42-w
/usr/share/terminfo/w/wy160-43
/usr/share/terminfo/w/wy160-43-w
/usr/share/terminfo/w/wy160-tek
/usr/share/terminfo/w/wy160-vb
/usr/share/terminfo/w/wy160-w
/usr/share/terminfo/w/wy160-w-vb
/usr/share/terminfo/w/wy185
/usr/share/terminfo/w/wy185-24
/usr/share/terminfo/w/wy185-vb
/usr/share/terminfo/w/wy185-w
/usr/share/terminfo/w/wy185-wvb
/usr/share/terminfo/w/wy30
/usr/share/terminfo/w/wy30-mc
/usr/share/terminfo/w/wy30-vb
/usr/share/terminfo/w/wy325
/usr/share/terminfo/w/wy325-25
/usr/share/terminfo/w/wy325-25w
/usr/share/terminfo/w/wy325-42
/usr/share/terminfo/w/wy325-42w
/usr/share/terminfo/w/wy325-42w-vb
/usr/share/terminfo/w/wy325-43
/usr/share/terminfo/w/wy325-43w
/usr/share/terminfo/w/wy325-43w-vb
/usr/share/terminfo/w/wy325-vb
/usr/share/terminfo/w/wy325-w
/usr/share/terminfo/w/wy325-w-vb
/usr/share/terminfo/w/wy350
/usr/share/terminfo/w/wy350-vb
/usr/share/terminfo/w/wy350-w
/usr/share/terminfo/w/wy350-wvb
/usr/share/terminfo/w/wy370
/usr/share/terminfo/w/wy370-105k
/usr/share/terminfo/w/wy370-EPC
/usr/share/terminfo/w/wy370-nk
/usr/share/terminfo/w/wy370-rv
/usr/share/terminfo/w/wy370-tek
/usr/share/terminfo/w/wy370-vb
/usr/share/terminfo/w/wy370-w
/usr/share/terminfo/w/wy370-wvb
/usr/share/terminfo/w/wy50
/usr/share/terminfo/w/wy50-mc
/usr/share/terminfo/w/wy50-vb
/usr/share/terminfo/w/wy50-w
/usr/share/terminfo/w/wy50-wvb
/usr/share/terminfo/w/wy520
/usr/share/terminfo/w/wy520-24
/usr/share/terminfo/w/wy520-36
/usr/share/terminfo/w/wy520-36pc
/usr/share/terminfo/w/wy520-36w
/usr/share/terminfo/w/wy520-36wpc
/usr/share/terminfo/w/wy520-48
/usr/share/terminfo/w/wy520-48pc
/usr/share/terminfo/w/wy520-48w
/usr/share/terminfo/w/wy520-48wpc
/usr/share/terminfo/w/wy520-epc
/usr/share/terminfo/w/wy520-epc-24
/usr/share/terminfo/w/wy520-epc-vb
/usr/share/terminfo/w/wy520-epc-w
/usr/share/terminfo/w/wy520-epc-wvb
/usr/share/terminfo/w/wy520-vb
/usr/share/terminfo/w/wy520-w
/usr/share/terminfo/w/wy520-wvb
/usr/share/terminfo/w/wy60
/usr/share/terminfo/w/wy60-25
/usr/share/terminfo/w/wy60-25-w
/usr/share/terminfo/w/wy60-42
/usr/share/terminfo/w/wy60-42-w
/usr/share/terminfo/w/wy60-43
/usr/share/terminfo/w/wy60-43-w
/usr/share/terminfo/w/wy60-vb
/usr/share/terminfo/w/wy60-w
/usr/share/terminfo/w/wy60-w-vb
/usr/share/terminfo/w/wy75
/usr/share/terminfo/w/wy75-mc
/usr/share/terminfo/w/wy75-vb
/usr/share/terminfo/w/wy75-w
/usr/share/terminfo/w/wy75-wvb
/usr/share/terminfo/w/wy75ap
/usr/share/terminfo/w/wy85
/usr/share/terminfo/w/wy85-8bit
/usr/share/terminfo/w/wy85-vb
/usr/share/terminfo/w/wy85-w
/usr/share/terminfo/w/wy85-wvb
/usr/share/terminfo/w/wy99-ansi
/usr/share/terminfo/w/wy99a-ansi
/usr/share/terminfo/w/wy99f
/usr/share/terminfo/w/wy99fa
/usr/share/terminfo/w/wy99gt
/usr/share/terminfo/w/wy99gt-25
/usr/share/terminfo/w/wy99gt-25-w
/usr/share/terminfo/w/wy99gt-tek
/usr/share/terminfo/w/wy99gt-vb
/usr/share/terminfo/w/wy99gt-w
/usr/share/terminfo/w/wy99gt-w-vb
/usr/share/terminfo/w/wyse+sl
/usr/share/terminfo/w/wyse-vp
/usr/share/terminfo/x
/usr/share/terminfo/x/x10term
/usr/share/terminfo/x/x10term+sl
/usr/share/terminfo/x/x68k
/usr/share/terminfo/x/xerox1720
/usr/share/terminfo/x/xerox820
/usr/share/terminfo/x/xfce
/usr/share/terminfo/x/xgterm
/usr/share/terminfo/x/xiterm
/usr/share/terminfo/x/xnuppc
/usr/share/terminfo/x/xnuppc+100x37
/usr/share/terminfo/x/xnuppc+112x37
/usr/share/terminfo/x/xnuppc+128x40
/usr/share/terminfo/x/xnuppc+128x48
/usr/share/terminfo/x/xnuppc+144x48
/usr/share/terminfo/x/xnuppc+160x64
/usr/share/terminfo/x/xnuppc+200x64
/usr/share/terminfo/x/xnuppc+200x75
/usr/share/terminfo/x/xnuppc+256x96
/usr/share/terminfo/x/xnuppc+80x25
/usr/share/terminfo/x/xnuppc+80x30
/usr/share/terminfo/x/xnuppc+90x30
/usr/share/terminfo/x/xnuppc+b
/usr/share/terminfo/x/xnuppc+basic
/usr/share/terminfo/x/xnuppc+c
/usr/share/terminfo/x/xnuppc+f
/usr/share/terminfo/x/xnuppc+f2
/usr/share/terminfo/x/xnuppc-100x37
/usr/share/terminfo/x/xnuppc-100x37-m
/usr/share/terminfo/x/xnuppc-112x37
/usr/share/terminfo/x/xnuppc-112x37-m
/usr/share/terminfo/x/xnuppc-128x40
/usr/share/terminfo/x/xnuppc-128x40-m
/usr/share/terminfo/x/xnuppc-128x48
/usr/share/terminfo/x/xnuppc-128x48-m
/usr/share/terminfo/x/xnuppc-144x48
/usr/share/terminfo/x/xnuppc-144x48-m
/usr/share/terminfo/x/xnuppc-160x64
/usr/share/terminfo/x/xnuppc-160x64-m
/usr/share/terminfo/x/xnuppc-200x64
/usr/share/terminfo/x/xnuppc-200x64-m
/usr/share/terminfo/x/xnuppc-200x75
/usr/share/terminfo/x/xnuppc-200x75-m
/usr/share/terminfo/x/xnuppc-256x96
/usr/share/terminfo/x/xnuppc-256x96-m
/usr/share/terminfo/x/xnuppc-80x25
/usr/share/terminfo/x/xnuppc-80x25-m
/usr/share/terminfo/x/xnuppc-80x30
/usr/share/terminfo/x/xnuppc-80x30-m
/usr/share/terminfo/x/xnuppc-90x30
/usr/share/terminfo/x/xnuppc-90x30-m
/usr/share/terminfo/x/xnuppc-b
/usr/share/terminfo/x/xnuppc-f
/usr/share/terminfo/x/xnuppc-f2
/usr/share/terminfo/x/xnuppc-m
/usr/share/terminfo/x/xnuppc-m-b
/usr/share/terminfo/x/xnuppc-m-f
/usr/share/terminfo/x/xnuppc-m-f2
/usr/share/terminfo/x/xtalk
/usr/share/terminfo/x/xterm+256color
/usr/share/terminfo/x/xterm+256color2
/usr/share/terminfo/x/xterm+256setaf
/usr/share/terminfo/x/xterm+88color
/usr/share/terminfo/x/xterm+88color2
/usr/share/terminfo/x/xterm+acs
/usr/share/terminfo/x/xterm+alt+title
/usr/share/terminfo/x/xterm+alt1049
/usr/share/terminfo/x/xterm+alt47
/usr/share/terminfo/x/xterm+app
/usr/share/terminfo/x/xterm+direct
/usr/share/terminfo/x/xterm+direct16
/usr/share/terminfo/x/xterm+direct2
/usr/share/terminfo/x/xterm+direct256
/usr/share/terminfo/x/xterm+edit
/usr/share/terminfo/x/xterm+focus
/usr/share/terminfo/x/xterm+indirect
/usr/share/terminfo/x/xterm+kbs
/usr/share/terminfo/x/xterm+keypad
/usr/share/terminfo/x/xterm+meta
/usr/share/terminfo/x/xterm+noalt
/usr/share/terminfo/x/xterm+noapp
/usr/share/terminfo/x/xterm+nofkeys
/usr/share/terminfo/x/xterm+nopcfkeys
/usr/share/terminfo/x/xterm+osc104
/usr/share/terminfo/x/xterm+pc+edit
/usr/share/terminfo/x/xterm+pcc0
/usr/share/terminfo/x/xterm+pcc1
/usr/share/terminfo/x/xterm+pcc2
/usr/share/terminfo/x/xterm+pcc3
/usr/share/terminfo/x/xterm+pce2
/usr/share/terminfo/x/xterm+pcf0
/usr/share/terminfo/x/xterm+pcf2
/usr/share/terminfo/x/xterm+pcfkeys
/usr/share/terminfo/x/xterm+r6f2
/usr/share/terminfo/x/xterm+sl
/usr/share/terminfo/x/xterm+sl-alt
/usr/share/terminfo/x/xterm+sl-twm
/usr/share/terminfo/x/xterm+sm+1002
/usr/share/terminfo/x/xterm+sm+1003
/usr/share/terminfo/x/xterm+sm+1005
/usr/share/terminfo/x/xterm+sm+1006
/usr/share/terminfo/x/xterm+titlestack
/usr/share/terminfo/x/xterm+tmux
/usr/share/terminfo/x/xterm+tmux2
/usr/share/terminfo/x/xterm+vt+edit
/usr/share/terminfo/x/xterm+x10mouse
/usr/share/terminfo/x/xterm+x11hilite
/usr/share/terminfo/x/xterm+x11mouse
/usr/share/terminfo/x/xterm-1002
/usr/share/terminfo/x/xterm-1003
/usr/share/terminfo/x/xterm-1005
/usr/share/terminfo/x/xterm-1006
/usr/share/terminfo/x/xterm-16color
/usr/share/terminfo/x/xterm-24
/usr/share/terminfo/x/xterm-88color
/usr/share/terminfo/x/xterm-8bit
/usr/share/terminfo/x/xterm-basic
/usr/share/terminfo/x/xterm-bold
/usr/share/terminfo/x/xterm-direct
/usr/share/terminfo/x/xterm-direct16
/usr/share/terminfo/x/xterm-direct2
/usr/share/terminfo/x/xterm-direct256
/usr/share/terminfo/x/xterm-hp
/usr/share/terminfo/x/xterm-new
/usr/share/terminfo/x/xterm-nic
/usr/share/terminfo/x/xterm-noapp
/usr/share/terminfo/x/xterm-old
/usr/share/terminfo/x/xterm-p370
/usr/share/terminfo/x/xterm-p371
/usr/share/terminfo/x/xterm-pcolor
/usr/share/terminfo/x/xterm-sco
/usr/share/terminfo/x/xterm-sun
/usr/share/terminfo/x/xterm-utf8
/usr/share/terminfo/x/xterm-vt52
/usr/share/terminfo/x/xterm-x10mouse
/usr/share/terminfo/x/xterm-x11hilite
/usr/share/terminfo/x/xterm-x11mouse
/usr/share/terminfo/x/xterm-xf86-v32
/usr/share/terminfo/x/xterm-xf86-v33
/usr/share/terminfo/x/xterm-xf86-v333
/usr/share/terminfo/x/xterm-xf86-v40
/usr/share/terminfo/x/xterm-xf86-v43
/usr/share/terminfo/x/xterm-xf86-v44
/usr/share/terminfo/x/xterm-xi
/usr/share/terminfo/x/xterm1
/usr/share/terminfo/x/xtermc
/usr/share/terminfo/x/xtermm
/usr/share/terminfo/x/xterms-sun
/usr/share/terminfo/z
/usr/share/terminfo/z/z100
/usr/share/terminfo/z/z100bw
/usr/share/terminfo/z/z29
/usr/share/terminfo/z/z29a
/usr/share/terminfo/z/z29a-kc-uc
/usr/share/terminfo/z/z29a-nkc-bc
/usr/share/terminfo/z/z29a-nkc-uc
/usr/share/terminfo/z/z340
/usr/share/terminfo/z/z340-nam
/usr/share/terminfo/z/z39-a
/usr/share/terminfo/z/zen30
/usr/share/terminfo/z/zen50
/usr/share/terminfo/z/ztx
/usr/share/terminfo/1/1178
/usr/share/terminfo/1/1730-lm
/usr/share/terminfo/2/2621
/usr/share/terminfo/2/2621-wl
/usr/share/terminfo/2/2621A
/usr/share/terminfo/2/2621a
/usr/share/terminfo/3/386at
/usr/share/terminfo/3/3b1
/usr/share/terminfo/4/4025ex
/usr/share/terminfo/4/4027ex
/usr/share/terminfo/4/4410-w
/usr/share/terminfo/5/5051
/usr/share/terminfo/5/5410-w
/usr/share/terminfo/5/5620
/usr/share/terminfo/5/5630-24
/usr/share/terminfo/5/5630DMD-24
/usr/share/terminfo/6/6053
/usr/share/terminfo/6/6053-dg
/usr/share/terminfo/6/605x
/usr/share/terminfo/6/605x-dg
/usr/share/terminfo/6/630-lm
/usr/share/terminfo/6/630MTG-24
/usr/share/terminfo/7/730MTG-24
/usr/share/terminfo/7/730MTG-41
/usr/share/terminfo/7/730MTG-41r
/usr/share/terminfo/7/730MTGr
/usr/share/terminfo/7/730MTGr-24
/usr/share/terminfo/8/8510
/usr/share/terminfo/9/955-hb
/usr/share/terminfo/9/955-w
/usr/share/terminfo/A/Apple_Terminal
/usr/share/terminfo/L/LFT-PC850
/usr/share/terminfo/N/NCR260VT300WPP
/usr/share/terminfo/N/NCRVT100WPP
/usr/share/terminfo/P/P12
/usr/share/terminfo/P/P12-M
/usr/share/terminfo/P/P12-M-W
/usr/share/terminfo/P/P12-W
/usr/share/terminfo/P/P14
/usr/share/terminfo/P/P14-M
/usr/share/terminfo/P/P14-M-W
/usr/share/terminfo/P/P14-W
/usr/share/terminfo/P/P4
/usr/share/terminfo/P/P5
/usr/share/terminfo/P/P7
/usr/share/terminfo/P/P8
/usr/share/terminfo/P/P8-W
/usr/share/terminfo/P/P9
/usr/share/terminfo/P/P9-8
/usr/share/terminfo/P/P9-8-W
/usr/share/terminfo/P/P9-W
/usr/share/terminfo/Q/Q306-8-pc
/usr/share/terminfo/Q/Q310-vip-H
/usr/share/terminfo/Q/Q310-vip-H-am
/usr/share/terminfo/Q/Q310-vip-Hw
/usr/share/terminfo/Q/Q310-vip-w
/usr/share/terminfo/Q/Q310-vip-w-am
/usr/share/terminfo/X/X-hpterm
/usr/share/terminfo/X/X-hpterm-color2
/usr/share/terminfo/a/a210
/usr/share/terminfo/a/a80
/usr/share/terminfo/a/a980
/usr/share/terminfo/a/aa4080
/usr/share/terminfo/a/aaa-30
/usr/share/terminfo/a/aaa-30-s-ctxt
/usr/share/terminfo/a/aaa-30-s-rv-ct
/usr/share/terminfo/a/aaa-ctxt
/usr/share/terminfo/a/aaa-rv
/usr/share/terminfo/a/aaa-rv-ctxt
/usr/share/terminfo/a/aaa-s
/usr/share/terminfo/a/aaa-s-rv
/usr/share/terminfo/a/aaa-unk
/usr/share/terminfo/a/adds200
/usr/share/terminfo/a/addsviewpoint
/usr/share/terminfo/a/addsvp60
/usr/share/terminfo/a/adm1
/usr/share/terminfo/a/aj
/usr/share/terminfo/a/aj832
/usr/share/terminfo/a/alt2
/usr/share/terminfo/a/alt3
/usr/share/terminfo/a/alt4
/usr/share/terminfo/a/alt5
/usr/share/terminfo/a/alt7
/usr/share/terminfo/a/alt7pc
/usr/share/terminfo/a/alto-heath
/usr/share/terminfo/a/altoh19
/usr/share/terminfo/a/altoheath
/usr/share/terminfo/a/altos-2
/usr/share/terminfo/a/altos-3
/usr/share/terminfo/a/altos-4
/usr/share/terminfo/a/altos-5
/usr/share/terminfo/a/altos5
/usr/share/terminfo/a/ambas
/usr/share/terminfo/a/ambassador
/usr/share/terminfo/a/amp219
/usr/share/terminfo/a/amp219w
/usr/share/terminfo/a/ampex-219
/usr/share/terminfo/a/ampex-219w
/usr/share/terminfo/a/ampex-232
/usr/share/terminfo/a/ansi-mono
/usr/share/terminfo/a/ansi43m
/usr/share/terminfo/a/ansi80x25
/usr/share/terminfo/a/ansi80x25-mono
/usr/share/terminfo/a/ansi80x25-raw
/usr/share/terminfo/a/ansi80x30
/usr/share/terminfo/a/ansi80x30-mono
/usr/share/terminfo/a/ansi80x43
/usr/share/terminfo/a/ansi80x43-mono
/usr/share/terminfo/a/ansi80x50
/usr/share/terminfo/a/ansi80x50-mono
/usr/share/terminfo/a/ansi80x60
/usr/share/terminfo/a/ansi80x60-mono
/usr/share/terminfo/a/ansil
/usr/share/terminfo/a/ansil-mono
/usr/share/terminfo/a/ansis
/usr/share/terminfo/a/ansis-mono
/usr/share/terminfo/a/ansisysk
/usr/share/terminfo/a/ansiterm
/usr/share/terminfo/a/ansiw
/usr/share/terminfo/a/ap-vm80
/usr/share/terminfo/a/apl
/usr/share/terminfo/a/appleIIc
/usr/share/terminfo/a/appleIIe
/usr/share/terminfo/a/arm100-am
/usr/share/terminfo/a/arm100-wam
/usr/share/terminfo/a/at
/usr/share/terminfo/a/at-color
/usr/share/terminfo/a/at-m
/usr/share/terminfo/a/at386
/usr/share/terminfo/a/atari
/usr/share/terminfo/a/atari-color
/usr/share/terminfo/a/atari-m
/usr/share/terminfo/a/atari_st
/usr/share/terminfo/a/atari_st-color
/usr/share/terminfo/a/atarist-m
/usr/share/terminfo/a/att4410-w
/usr/share/terminfo/a/att4410v1
/usr/share/terminfo/a/att4425
/usr/share/terminfo/a/att4425-nl
/usr/share/terminfo/a/att4425-w
/usr/share/terminfo/a/att513
/usr/share/terminfo/a/att5320
/usr/share/terminfo/a/att5410
/usr/share/terminfo/a/att5410v1-w
/usr/share/terminfo/a/att5418
/usr/share/terminfo/a/att5418-w
/usr/share/terminfo/a/att5420
/usr/share/terminfo/a/att5420+nl
/usr/share/terminfo/a/att5420-nl
/usr/share/terminfo/a/att5420-rv
/usr/share/terminfo/a/att5420-rv-nl
/usr/share/terminfo/a/att5420-w
/usr/share/terminfo/a/att5420-w-nl
/usr/share/terminfo/a/att5420-w-rv
/usr/share/terminfo/a/att5420-w-rv-n
/usr/share/terminfo/a/att5430
/usr/share/terminfo/a/avatar1
/usr/share/terminfo/a/avt-rv-s
/usr/share/terminfo/a/avt-s
/usr/share/terminfo/a/avt-w-rv-s
/usr/share/terminfo/a/avt-w-s
/usr/share/terminfo/b/b-128
/usr/share/terminfo/b/basic4
/usr/share/terminfo/b/bct510a
/usr/share/terminfo/b/bct510d
/usr/share/terminfo/b/bee
/usr/share/terminfo/b/beehiveIIIm
/usr/share/terminfo/b/bg2.0nv
/usr/share/terminfo/b/bg3.10
/usr/share/terminfo/b/bg3.10nv
/usr/share/terminfo/b/bg3.10rv
/usr/share/terminfo/b/bh3m
/usr/share/terminfo/b/bh4
/usr/share/terminfo/b/bsdos-pc-mono
/usr/share/terminfo/c/c100-1p
/usr/share/terminfo/c/c100-4p
/usr/share/terminfo/c/c100-rv-4p
/usr/share/terminfo/c/c104
/usr/share/terminfo/c/c108-8p
/usr/share/terminfo/c/c108-rv-8p
/usr/share/terminfo/c/c108-w-8p
/usr/share/terminfo/c/c300
/usr/share/terminfo/c/c301
/usr/share/terminfo/c/c321
/usr/share/terminfo/c/cci1
/usr/share/terminfo/c/cgc2
/usr/share/terminfo/c/cgc3
/usr/share/terminfo/c/chromatics
/usr/share/terminfo/c/ci8510
/usr/share/terminfo/c/cit-80
/usr/share/terminfo/c/citc
/usr/share/terminfo/c/citoh-ps
/usr/share/terminfo/c/coherent
/usr/share/terminfo/c/colorscan
/usr/share/terminfo/c/concept
/usr/share/terminfo/c/concept-avt
/usr/share/terminfo/c/concept100
/usr/share/terminfo/c/concept100-rv
/usr/share/terminfo/c/concept108
/usr/share/terminfo/c/concept108-4p
/usr/share/terminfo/c/concept108-8p
/usr/share/terminfo/c/concept108-w-8
/usr/share/terminfo/c/concept108-w8p
/usr/share/terminfo/c/concept108rv4p
/usr/share/terminfo/c/cons25
/usr/share/terminfo/c/cons25-iso-m
/usr/share/terminfo/c/cons25-iso8859
/usr/share/terminfo/c/cons25-koi8-r
/usr/share/terminfo/c/cons25-koi8r-m
/usr/share/terminfo/c/cons50-iso-m
/usr/share/terminfo/c/cons50-iso8859
/usr/share/terminfo/c/cons50-koi8r
/usr/share/terminfo/c/cons50-koi8r-m
/usr/share/terminfo/c/cons60-iso
/usr/share/terminfo/c/cons60-iso-m
/usr/share/terminfo/c/cons60-koi8r
/usr/share/terminfo/c/cons60-koi8r-m
/usr/share/terminfo/c/contel320
/usr/share/terminfo/c/contel321
/usr/share/terminfo/c/cops
/usr/share/terminfo/c/cops-10
/usr/share/terminfo/c/crt-vt220
/usr/share/terminfo/c/ct82
/usr/share/terminfo/c/cx
/usr/share/terminfo/c/cx100
/usr/share/terminfo/d/d2
/usr/share/terminfo/d/d2-dg
/usr/share/terminfo/d/d200-dg
/usr/share/terminfo/d/d214
/usr/share/terminfo/d/d214-dg
/usr/share/terminfo/d/d215
/usr/share/terminfo/d/d215-7b
/usr/share/terminfo/d/d215-dg
/usr/share/terminfo/d/d216+
/usr/share/terminfo/d/d216+25
/usr/share/terminfo/d/d216+dg
/usr/share/terminfo/d/d216e+
/usr/share/terminfo/d/d216e+dg
/usr/share/terminfo/d/d216e-dg
/usr/share/terminfo/d/d216e-unix
/usr/share/terminfo/d/d217-dg
/usr/share/terminfo/d/d230
/usr/share/terminfo/d/d230-dg
/usr/share/terminfo/d/d400-dg
/usr/share/terminfo/d/d411
/usr/share/terminfo/d/d411-7b
/usr/share/terminfo/d/d411-7b-w
/usr/share/terminfo/d/d411-dg
/usr/share/terminfo/d/d411-w
/usr/share/terminfo/d/d412+
/usr/share/terminfo/d/d412+25
/usr/share/terminfo/d/d412+dg
/usr/share/terminfo/d/d412+s
/usr/share/terminfo/d/d412+sr
/usr/share/terminfo/d/d412+w
/usr/share/terminfo/d/d413-dg
/usr/share/terminfo/d/d430-dg
/usr/share/terminfo/d/d430-dg-ccc
/usr/share/terminfo/d/d430-unix
/usr/share/terminfo/d/d430-unix-25
/usr/share/terminfo/d/d430-unix-25-ccc
/usr/share/terminfo/d/d430-unix-ccc
/usr/share/terminfo/d/d430-unix-s
/usr/share/terminfo/d/d430-unix-s-ccc
/usr/share/terminfo/d/d430-unix-sr
/usr/share/terminfo/d/d430-unix-sr-ccc
/usr/share/terminfo/d/d430-unix-w
/usr/share/terminfo/d/d430-unix-w-ccc
/usr/share/terminfo/d/d450
/usr/share/terminfo/d/d450-dg
/usr/share/terminfo/d/d460
/usr/share/terminfo/d/d460-7b
/usr/share/terminfo/d/d460-7b-w
/usr/share/terminfo/d/d460-dg
/usr/share/terminfo/d/d460-w
/usr/share/terminfo/d/d461
/usr/share/terminfo/d/d461-7b
/usr/share/terminfo/d/d461-7b-w
/usr/share/terminfo/d/d461-dg
/usr/share/terminfo/d/d461-w
/usr/share/terminfo/d/d462+
/usr/share/terminfo/d/d462+25
/usr/share/terminfo/d/d462+dg
/usr/share/terminfo/d/d462+s
/usr/share/terminfo/d/d462+sr
/usr/share/terminfo/d/d462+w
/usr/share/terminfo/d/d462-dg
/usr/share/terminfo/d/d462-unix
/usr/share/terminfo/d/d462-unix-25
/usr/share/terminfo/d/d462-unix-s
/usr/share/terminfo/d/d462-unix-sr
/usr/share/terminfo/d/d462-unix-w
/usr/share/terminfo/d/d462e-dg
/usr/share/terminfo/d/d463-dg
/usr/share/terminfo/d/d463-unix
/usr/share/terminfo/d/d463-unix-25
/usr/share/terminfo/d/d463-unix-s
/usr/share/terminfo/d/d463-unix-sr
/usr/share/terminfo/d/d463-unix-w
/usr/share/terminfo/d/d464-unix
/usr/share/terminfo/d/d464-unix-25
/usr/share/terminfo/d/d464-unix-s
/usr/share/terminfo/d/d464-unix-sr
/usr/share/terminfo/d/d464-unix-w
/usr/share/terminfo/d/d470
/usr/share/terminfo/d/d470-7b
/usr/share/terminfo/d/d470-dg
/usr/share/terminfo/d/d578-dg
/usr/share/terminfo/d/d80
/usr/share/terminfo/d/darwin
/usr/share/terminfo/d/darwin-100x37
/usr/share/terminfo/d/darwin-100x37-m
/usr/share/terminfo/d/darwin-112x37
/usr/share/terminfo/d/darwin-112x37-m
/usr/share/terminfo/d/darwin-128x40
/usr/share/terminfo/d/darwin-128x40-m
/usr/share/terminfo/d/darwin-128x48
/usr/share/terminfo/d/darwin-128x48-m
/usr/share/terminfo/d/darwin-144x48
/usr/share/terminfo/d/darwin-144x48-m
/usr/share/terminfo/d/darwin-160x64
/usr/share/terminfo/d/darwin-160x64-m
/usr/share/terminfo/d/darwin-200x64
/usr/share/terminfo/d/darwin-200x64-m
/usr/share/terminfo/d/darwin-200x75
/usr/share/terminfo/d/darwin-200x75-m
/usr/share/terminfo/d/darwin-256x96
/usr/share/terminfo/d/darwin-256x96-m
/usr/share/terminfo/d/darwin-80x25
/usr/share/terminfo/d/darwin-80x25-m
/usr/share/terminfo/d/darwin-80x30
/usr/share/terminfo/d/darwin-80x30-m
/usr/share/terminfo/d/darwin-90x30
/usr/share/terminfo/d/darwin-90x30-m
/usr/share/terminfo/d/darwin-b
/usr/share/terminfo/d/darwin-f
/usr/share/terminfo/d/darwin-f2
/usr/share/terminfo/d/darwin-m
/usr/share/terminfo/d/darwin-m-b
/usr/share/terminfo/d/darwin-m-f
/usr/share/terminfo/d/darwin-m-f2
/usr/share/terminfo/d/datagraphix
/usr/share/terminfo/d/datamedia2500
/usr/share/terminfo/d/datapoint
/usr/share/terminfo/d/dataspeed40
/usr/share/terminfo/d/dd5000
/usr/share/terminfo/d/ddr3180
/usr/share/terminfo/d/dec-vt330
/usr/share/terminfo/d/dec-vt340
/usr/share/terminfo/d/dec-vt400
/usr/share/terminfo/d/decpro
/usr/share/terminfo/d/decwriter
/usr/share/terminfo/d/dg-ansi
/usr/share/terminfo/d/dg100
/usr/share/terminfo/d/dg605x
/usr/share/terminfo/d/dg6134
/usr/share/terminfo/d/diablo
/usr/share/terminfo/d/diablo-lm
/usr/share/terminfo/d/diablo1640-m8
/usr/share/terminfo/d/diablo1720
/usr/share/terminfo/d/diablo1730
/usr/share/terminfo/d/diablo1740
/usr/share/terminfo/d/diablo450
/usr/share/terminfo/d/diablo630
/usr/share/terminfo/d/dialogue
/usr/share/terminfo/d/dialogue80
/usr/share/terminfo/d/dku7102
/usr/share/terminfo/d/dku7102-sna
/usr/share/terminfo/d/dku7103-sna
/usr/share/terminfo/d/dm1521
/usr/share/terminfo/d/dmd
/usr/share/terminfo/d/dmd-24
/usr/share/terminfo/d/dmd-34
/usr/share/terminfo/d/dmd1
/usr/share/terminfo/d/dmdt80
/usr/share/terminfo/d/dmdt80w
/usr/share/terminfo/d/ds40
/usr/share/terminfo/d/ds40-2
/usr/share/terminfo/d/dt-100
/usr/share/terminfo/d/dt-100w
/usr/share/terminfo/d/dt80
/usr/share/terminfo/d/dt80w
/usr/share/terminfo/d/dw
/usr/share/terminfo/d/dwk-vt
/usr/share/terminfo/e/emots
/usr/share/terminfo/e/envision230
/usr/share/terminfo/e/ep4000
/usr/share/terminfo/e/ep4080
/usr/share/terminfo/e/excel64
/usr/share/terminfo/e/excel64-rv
/usr/share/terminfo/e/excel64-w
/usr/share/terminfo/e/exec80
/usr/share/terminfo/f/f1720a
/usr/share/terminfo/f/fenix
/usr/share/terminfo/f/fenixw
/usr/share/terminfo/f/fixterm
/usr/share/terminfo/f/fortune
/usr/share/terminfo/f/freedom
/usr/share/terminfo/f/freedom-rv
/usr/share/terminfo/f/freedom100
/usr/share/terminfo/f/freedom110
/usr/share/terminfo/f/freedom200
/usr/share/terminfo/g/go-225
/usr/share/terminfo/g/gs5430
/usr/share/terminfo/g/gs5430-22
/usr/share/terminfo/g/gs5430-24
/usr/share/terminfo/g/gt100
/usr/share/terminfo/g/gt100a
/usr/share/terminfo/g/guru+unk
/usr/share/terminfo/g/guru-33
/usr/share/terminfo/g/guru-33-rv
/usr/share/terminfo/g/guru-33-s
/usr/share/terminfo/g/guru-lp
/usr/share/terminfo/h/h-100
/usr/share/terminfo/h/h-100bw
/usr/share/terminfo/h/h100
/usr/share/terminfo/h/h100bw
/usr/share/terminfo/h/h19-b
/usr/share/terminfo/h/h19-smul
/usr/share/terminfo/h/h19a
/usr/share/terminfo/h/h19g
/usr/share/terminfo/h/h19kermit
/usr/share/terminfo/h/h19us
/usr/share/terminfo/h/h29a-kc-bc
/usr/share/terminfo/h/h29a-kc-uc
/usr/share/terminfo/h/h29a-nkc-bc
/usr/share/terminfo/h/h29a-nkc-uc
/usr/share/terminfo/h/h80
/usr/share/terminfo/h/he80
/usr/share/terminfo/h/heath
/usr/share/terminfo/h/heath-19
/usr/share/terminfo/h/heath-ansi
/usr/share/terminfo/h/heathkit
/usr/share/terminfo/h/heathkit-a
/usr/share/terminfo/h/hft
/usr/share/terminfo/h/hp
/usr/share/terminfo/h/hp2382
/usr/share/terminfo/h/hp2397
/usr/share/terminfo/h/hp2621-wl
/usr/share/terminfo/h/hp2621A
/usr/share/terminfo/h/hp2621a
/usr/share/terminfo/h/hp2621a-a
/usr/share/terminfo/h/hp2621k45
/usr/share/terminfo/h/hp2622a
/usr/share/terminfo/h/hp2623a
/usr/share/terminfo/h/hp2624a
/usr/share/terminfo/h/hp2624a-10p
/usr/share/terminfo/h/hp2624b
/usr/share/terminfo/h/hp2624b-10p
/usr/share/terminfo/h/hp2624b-4p
/usr/share/terminfo/h/hp2624b-4p-p
/usr/share/terminfo/h/hp2626a
/usr/share/terminfo/h/hp2626p
/usr/share/terminfo/h/hp2644a
/usr/share/terminfo/h/hp2645a
/usr/share/terminfo/h/hp2647a
/usr/share/terminfo/h/hp2648a
/usr/share/terminfo/h/hp45
/usr/share/terminfo/h/hp700
/usr/share/terminfo/h/hp70092A
/usr/share/terminfo/h/hp70092a
/usr/share/terminfo/h/hp98550a
/usr/share/terminfo/h/hp98550a-color
/usr/share/terminfo/h/hp98720
/usr/share/terminfo/h/hp98721
/usr/share/terminfo/h/hpex2
/usr/share/terminfo/h/htx11
/usr/share/terminfo/i/i3101
/usr/share/terminfo/i/i3164
/usr/share/terminfo/i/ibm3163
/usr/share/terminfo/i/ibm5051
/usr/share/terminfo/i/ibm5154-c
/usr/share/terminfo/i/ibm6154-c
/usr/share/terminfo/i/ibm8507
/usr/share/terminfo/i/ibm8513
/usr/share/terminfo/i/ibm8604
/usr/share/terminfo/i/ibmapa16
/usr/share/terminfo/i/ibmapa8
/usr/share/terminfo/i/ibmmpel-c
/usr/share/terminfo/i/ibmpc3r
/usr/share/terminfo/i/ibmpc3r-mono
/usr/share/terminfo/i/ibmx
/usr/share/terminfo/i/icl6402
/usr/share/terminfo/i/intertec
/usr/share/terminfo/i/intextii
/usr/share/terminfo/i/ips
/usr/share/terminfo/i/ipsi
/usr/share/terminfo/i/iq120
/usr/share/terminfo/i/iq140
/usr/share/terminfo/i/iris-ansi-net
/usr/share/terminfo/i/iris40
/usr/share/terminfo/i/iterm
/usr/share/terminfo/i/iterm2
/usr/share/terminfo/j/jerq
/usr/share/terminfo/k/k45
/usr/share/terminfo/k/kaypro2
/usr/share/terminfo/k/kds6402
/usr/share/terminfo/k/kds7372
/usr/share/terminfo/k/kds7372-w
/usr/share/terminfo/k/kon2
/usr/share/terminfo/k/kterm-co
/usr/share/terminfo/k/ktm
/usr/share/terminfo/l/la120
/usr/share/terminfo/l/layer
/usr/share/terminfo/l/lft-pc850
/usr/share/terminfo/l/luna68k
/usr/share/terminfo/m/macintosh
/usr/share/terminfo/m/macterminal-w
/usr/share/terminfo/m/mdl110
/usr/share/terminfo/m/microbee
/usr/share/terminfo/m/microterm
/usr/share/terminfo/m/microterm5
/usr/share/terminfo/m/mime-3ax
/usr/share/terminfo/m/mime1
/usr/share/terminfo/m/mime2
/usr/share/terminfo/m/mime2a-v
/usr/share/terminfo/m/mime340
/usr/share/terminfo/m/mimei
/usr/share/terminfo/m/mimeii
/usr/share/terminfo/m/minitel
/usr/share/terminfo/m/minitel-2
/usr/share/terminfo/m/minitel-2-nam
/usr/share/terminfo/m/minix-1.5
/usr/share/terminfo/m/mm314
/usr/share/terminfo/m/mod
/usr/share/terminfo/m/mod24
/usr/share/terminfo/m/mouse-sun
/usr/share/terminfo/m/mskermit227
/usr/share/terminfo/m/mskermit22714
/usr/share/terminfo/m/mskermit227am
/usr/share/terminfo/m/mt-70
/usr/share/terminfo/n/n7900
/usr/share/terminfo/n/nansisys
/usr/share/terminfo/n/nansisysk
/usr/share/terminfo/n/ncr7900
/usr/share/terminfo/n/ncrvt100pp
/usr/share/terminfo/n/ncrvt100wpp
/usr/share/terminfo/n/ncsa-vt220-8
/usr/share/terminfo/n/nd9500
/usr/share/terminfo/n/nec
/usr/share/terminfo/n/news
/usr/share/terminfo/n/news-a
/usr/share/terminfo/n/news-o
/usr/share/terminfo/n/news28-a
/usr/share/terminfo/n/news31
/usr/share/terminfo/n/news31-a
/usr/share/terminfo/n/news31-o
/usr/share/terminfo/n/news33
/usr/share/terminfo/n/news40
/usr/share/terminfo/n/news40-a
/usr/share/terminfo/n/news40-o
/usr/share/terminfo/n/news42
/usr/share/terminfo/n/newscbm
/usr/share/terminfo/n/newscbm-a
/usr/share/terminfo/n/newscbm-o
/usr/share/terminfo/n/newscbm33
/usr/share/terminfo/n/nsterm-256color
/usr/share/terminfo/n/nsterm-7-c-s
/usr/share/terminfo/n/nsterm-7-m
/usr/share/terminfo/n/nsterm-7-m-s
/usr/share/terminfo/n/nsterm-7-s
/usr/share/terminfo/n/nsterm-acs-c
/usr/share/terminfo/n/nsterm-acs-c-s
/usr/share/terminfo/n/nsterm-acs-m
/usr/share/terminfo/n/nsterm-acs-m-s
/usr/share/terminfo/n/nsterm-acs-s
/usr/share/terminfo/n/nsterm-c-7
/usr/share/terminfo/n/ntconsole
/usr/share/terminfo/n/ntconsole-100
/usr/share/terminfo/n/ntconsole-100-nti
/usr/share/terminfo/n/ntconsole-25
/usr/share/terminfo/n/ntconsole-25-nti
/usr/share/terminfo/n/ntconsole-25-w
/usr/share/terminfo/n/ntconsole-25-w-vt
/usr/share/terminfo/n/ntconsole-35
/usr/share/terminfo/n/ntconsole-35-nti
/usr/share/terminfo/n/ntconsole-35-w
/usr/share/terminfo/n/ntconsole-50
/usr/share/terminfo/n/ntconsole-50-nti
/usr/share/terminfo/n/ntconsole-50-w
/usr/share/terminfo/n/ntconsole-60
/usr/share/terminfo/n/ntconsole-60-nti
/usr/share/terminfo/n/ntconsole-60-w
/usr/share/terminfo/n/ntconsole-w
/usr/share/terminfo/n/ntconsole-w-vt
/usr/share/terminfo/n/nwe501
/usr/share/terminfo/n/nwe501-a
/usr/share/terminfo/n/nwe501-o
/usr/share/terminfo/n/nwp-511
/usr/share/terminfo/n/nwp-517
/usr/share/terminfo/n/nwp-517-w
/usr/share/terminfo/n/nwp251-a
/usr/share/terminfo/n/nwp251-o
/usr/share/terminfo/n/nwp512-o
/usr/share/terminfo/n/nwp513-o
/usr/share/terminfo/n/nwp514
/usr/share/terminfo/n/nwp514-a
/usr/share/terminfo/n/nwp514-o
/usr/share/terminfo/n/nwp518
/usr/share/terminfo/n/nwp518-a
/usr/share/terminfo/n/nwp518-o
/usr/share/terminfo/n/nxterm
/usr/share/terminfo/o/o31
/usr/share/terminfo/o/o4112-nd
/usr/share/terminfo/o/o85h
/usr/share/terminfo/o/oabm85h
/usr/share/terminfo/o/oconcept
/usr/share/terminfo/o/ojerq
/usr/share/terminfo/o/old-st
/usr/share/terminfo/o/oldibmpc3
/usr/share/terminfo/o/opennt
/usr/share/terminfo/o/opennt-25
/usr/share/terminfo/o/opennt-25-nti
/usr/share/terminfo/o/opennt-25-w
/usr/share/terminfo/o/opennt-25-w-vt
/usr/share/terminfo/o/opennt-nti
/usr/share/terminfo/o/origibmpc3
/usr/share/terminfo/o/os9LII
/usr/share/terminfo/o/osborne1
/usr/share/terminfo/o/osborne1-w
/usr/share/terminfo/o/otek4113
/usr/share/terminfo/o/otek4114
/usr/share/terminfo/p/p12
/usr/share/terminfo/p/p12-m
/usr/share/terminfo/p/p12-m-w
/usr/share/terminfo/p/p12-w
/usr/share/terminfo/p/p14
/usr/share/terminfo/p/p14-m
/usr/share/terminfo/p/p14-m-w
/usr/share/terminfo/p/p14-w
/usr/share/terminfo/p/p4
/usr/share/terminfo/p/p5
/usr/share/terminfo/p/p7
/usr/share/terminfo/p/p8
/usr/share/terminfo/p/p8-w
/usr/share/terminfo/p/p9
/usr/share/terminfo/p/p9-8
/usr/share/terminfo/p/p9-8-w
/usr/share/terminfo/p/p9-w
/usr/share/terminfo/p/pc3-bold
/usr/share/terminfo/p/pc3r
/usr/share/terminfo/p/pc3r-m
/usr/share/terminfo/p/pc7300
/usr/share/terminfo/p/pcansi-mono
/usr/share/terminfo/p/pcansi25
/usr/share/terminfo/p/pcansi25m
/usr/share/terminfo/p/pcansi33
/usr/share/terminfo/p/pcansi33m
/usr/share/terminfo/p/pcansi43
/usr/share/terminfo/p/pcconsole
/usr/share/terminfo/p/pckermit12
/usr/share/terminfo/p/pcz19
/usr/share/terminfo/p/pe1100
/usr/share/terminfo/p/pe1200
/usr/share/terminfo/p/pe550
/usr/share/terminfo/p/pe6100
/usr/share/terminfo/p/pe6300
/usr/share/terminfo/p/pe6312
/usr/share/terminfo/p/pmconsole
/usr/share/terminfo/p/printer
/usr/share/terminfo/p/prism8gl
/usr/share/terminfo/p/psterm-basic
/usr/share/terminfo/p/psx_ansi
/usr/share/terminfo/p/pt200
/usr/share/terminfo/p/pt200w
/usr/share/terminfo/p/pt505
/usr/share/terminfo/p/pt505-22
/usr/share/terminfo/p/pt505-24
/usr/share/terminfo/q/qdcons
/usr/share/terminfo/q/qnx4
/usr/share/terminfo/q/qnxt4
/usr/share/terminfo/q/qume
/usr/share/terminfo/q/qvt101p
/usr/share/terminfo/q/qvt108
/usr/share/terminfo/q/qvt119
/usr/share/terminfo/q/qvt119-25-w
/usr/share/terminfo/q/qvt119-w
/usr/share/terminfo/q/qvt119p
/usr/share/terminfo/q/qvt119p-25
/usr/share/terminfo/q/qvt119p-25-w
/usr/share/terminfo/q/qvt119p-w
/usr/share/terminfo/q/qvt203+
/usr/share/terminfo/q/qvt203-w-am
/usr/share/terminfo/r/rebus3180
/usr/share/terminfo/r/regent200
/usr/share/terminfo/r/rxvt
/usr/share/terminfo/r/rxvt-color
/usr/share/terminfo/s/s4
/usr/share/terminfo/s/sb3
/usr/share/terminfo/s/sbobcat
/usr/share/terminfo/s/sc410
/usr/share/terminfo/s/sc415
/usr/share/terminfo/s/screen.linux-s
/usr/share/terminfo/s/screen.minitel12-80
/usr/share/terminfo/s/screen.minitel2-80
/usr/share/terminfo/s/screen.xterm-new
/usr/share/terminfo/s/securecrt
/usr/share/terminfo/s/soroc
/usr/share/terminfo/s/spinwriter
/usr/share/terminfo/s/st52-m
/usr/share/terminfo/s/stterm
/usr/share/terminfo/s/stterm-16color
/usr/share/terminfo/s/stterm-256color
/usr/share/terminfo/s/sun
/usr/share/terminfo/s/sun-cmd
/usr/share/terminfo/s/sun-nic
/usr/share/terminfo/s/sun-s-e
/usr/share/terminfo/s/sun-ss5
/usr/share/terminfo/s/sun1
/usr/share/terminfo/s/sun2
/usr/share/terminfo/s/sune
/usr/share/terminfo/s/superbee
/usr/share/terminfo/s/sv80
/usr/share/terminfo/s/synertek380
/usr/share/terminfo/s/system1
/usr/share/terminfo/t/t653x
/usr/share/terminfo/t/tab
/usr/share/terminfo/t/tab132-15
/usr/share/terminfo/t/tek4012
/usr/share/terminfo/t/tek4025
/usr/share/terminfo/t/tek4027
/usr/share/terminfo/t/tek4027-ex
/usr/share/terminfo/t/tek4107brl
/usr/share/terminfo/t/tek4109
/usr/share/terminfo/t/tek4109brl
/usr/share/terminfo/t/tek4114
/usr/share/terminfo/t/teken-vt
/usr/share/terminfo/t/teleray
/usr/share/terminfo/t/terminet
/usr/share/terminfo/t/terminet300
/usr/share/terminfo/t/tgtelnet
/usr/share/terminfo/t/ti707
/usr/share/terminfo/t/ti707-w
/usr/share/terminfo/t/ti733
/usr/share/terminfo/t/ti735
/usr/share/terminfo/t/ti745
/usr/share/terminfo/t/ti800
/usr/share/terminfo/t/ti916-220-7
/usr/share/terminfo/t/ti916-220-8
/usr/share/terminfo/t/tkterm
/usr/share/terminfo/t/tn1200
/usr/share/terminfo/t/tn300
/usr/share/terminfo/t/trs80II
/usr/share/terminfo/t/trsII
/usr/share/terminfo/t/ts-1
/usr/share/terminfo/t/ts-1p
/usr/share/terminfo/t/ts1
/usr/share/terminfo/t/ts100-sp
/usr/share/terminfo/t/ts1p
/usr/share/terminfo/t/tty35
/usr/share/terminfo/t/tty4420
/usr/share/terminfo/t/tty4424
/usr/share/terminfo/t/tty4424-1
/usr/share/terminfo/t/tty4424m
/usr/share/terminfo/t/tty4426
/usr/share/terminfo/t/tty5410
/usr/share/terminfo/t/tty5410-w
/usr/share/terminfo/t/tty5410v1
/usr/share/terminfo/t/tty5410v1-w
/usr/share/terminfo/t/tty5420
/usr/share/terminfo/t/tty5420+nl
/usr/share/terminfo/t/tty5420-nl
/usr/share/terminfo/t/tty5420-rv
/usr/share/terminfo/t/tty5420-rv-nl
/usr/share/terminfo/t/tty5420-w
/usr/share/terminfo/t/tty5420-w-nl
/usr/share/terminfo/t/tty5420-w-rv
/usr/share/terminfo/t/tty5420-w-rv-n
/usr/share/terminfo/t/tty5425
/usr/share/terminfo/t/tty5425-nl
/usr/share/terminfo/t/tty5425-w
/usr/share/terminfo/t/tty5620
/usr/share/terminfo/t/tty5620-1
/usr/share/terminfo/t/tty5620-24
/usr/share/terminfo/t/tty5620-34
/usr/share/terminfo/t/tty5620-s
/usr/share/terminfo/t/ttydmd
/usr/share/terminfo/t/tvi912b-mc-2p
/usr/share/terminfo/t/tvi912b-mc-vb
/usr/share/terminfo/t/tvi912b-p-2p
/usr/share/terminfo/t/tvi912b-p-vb
/usr/share/terminfo/t/tvi912b-unk-2p
/usr/share/terminfo/t/tvi912b-unk-vb
/usr/share/terminfo/t/tvi912c
/usr/share/terminfo/t/tvi912c-2p
/usr/share/terminfo/t/tvi912c-2p-mc
/usr/share/terminfo/t/tvi912c-2p-p
/usr/share/terminfo/t/tvi912c-2p-unk
/usr/share/terminfo/t/tvi912c-mc
/usr/share/terminfo/t/tvi912c-mc-2p
/usr/share/terminfo/t/tvi912c-mc-vb
/usr/share/terminfo/t/tvi912c-p
/usr/share/terminfo/t/tvi912c-p-2p
/usr/share/terminfo/t/tvi912c-p-vb
/usr/share/terminfo/t/tvi912c-unk
/usr/share/terminfo/t/tvi912c-unk-2p
/usr/share/terminfo/t/tvi912c-unk-vb
/usr/share/terminfo/t/tvi912c-vb
/usr/share/terminfo/t/tvi912c-vb-mc
/usr/share/terminfo/t/tvi912c-vb-p
/usr/share/terminfo/t/tvi912c-vb-unk
/usr/share/terminfo/t/tvi914
/usr/share/terminfo/t/tvi920
/usr/share/terminfo/t/tvi920b-mc-2p
/usr/share/terminfo/t/tvi920b-mc-vb
/usr/share/terminfo/t/tvi920b-p-2p
/usr/share/terminfo/t/tvi920b-p-vb
/usr/share/terminfo/t/tvi920b-unk-2p
/usr/share/terminfo/t/tvi920b-unk-vb
/usr/share/terminfo/t/tvi920c
/usr/share/terminfo/t/tvi920c-2p
/usr/share/terminfo/t/tvi920c-2p-mc
/usr/share/terminfo/t/tvi920c-2p-p
/usr/share/terminfo/t/tvi920c-2p-unk
/usr/share/terminfo/t/tvi920c-mc
/usr/share/terminfo/t/tvi920c-mc-2p
/usr/share/terminfo/t/tvi920c-mc-vb
/usr/share/terminfo/t/tvi920c-p
/usr/share/terminfo/t/tvi920c-p-2p
/usr/share/terminfo/t/tvi920c-p-vb
/usr/share/terminfo/t/tvi920c-unk
/usr/share/terminfo/t/tvi920c-unk-2p
/usr/share/terminfo/t/tvi920c-unk-vb
/usr/share/terminfo/t/tvi920c-vb
/usr/share/terminfo/t/tvi920c-vb-mc
/usr/share/terminfo/t/tvi920c-vb-p
/usr/share/terminfo/t/tvi920c-vb-unk
/usr/share/terminfo/t/tw52-color
/usr/share/terminfo/u/ultima2
/usr/share/terminfo/u/ultimaII
/usr/share/terminfo/u/uniterm49
/usr/share/terminfo/u/unixpc
/usr/share/terminfo/v/v200-nam
/usr/share/terminfo/v/v320n
/usr/share/terminfo/v/vapple
/usr/share/terminfo/v/vc103
/usr/share/terminfo/v/vc203
/usr/share/terminfo/v/vc403a
/usr/share/terminfo/v/vc414h
/usr/share/terminfo/v/venix
/usr/share/terminfo/v/viewpoint3a+
/usr/share/terminfo/v/viewpoint60
/usr/share/terminfo/v/viewpoint90
/usr/share/terminfo/v/vip7800-H
/usr/share/terminfo/v/vip7800-Hw
/usr/share/terminfo/v/vip7800-w
/usr/share/terminfo/v/visual603
/usr/share/terminfo/v/vitty
/usr/share/terminfo/v/vk100
/usr/share/terminfo/v/vs100
/usr/share/terminfo/v/vs100-x10
/usr/share/terminfo/v/vt-61
/usr/share/terminfo/v/vt-utf8
/usr/share/terminfo/v/vt100
/usr/share/terminfo/v/vt100+
/usr/share/terminfo/v/vt100-am
/usr/share/terminfo/v/vt100-bm
/usr/share/terminfo/v/vt100-bm-o
/usr/share/terminfo/v/vt100-bot-s
/usr/share/terminfo/v/vt100-nam
/usr/share/terminfo/v/vt100-nam-w
/usr/share/terminfo/v/vt100-s-top
/usr/share/terminfo/v/vt100-top-s
/usr/share/terminfo/v/vt100-w-am
/usr/share/terminfo/v/vt100-w-nav
/usr/share/terminfo/v/vt200
/usr/share/terminfo/v/vt200-8
/usr/share/terminfo/v/vt200-8bit
/usr/share/terminfo/v/vt200-old
/usr/share/terminfo/v/vt200-w
/usr/share/terminfo/v/vt220
/usr/share/terminfo/v/vt220-8
/usr/share/terminfo/v/vt220-js
/usr/share/terminfo/v/vt300
/usr/share/terminfo/v/vt300-nam
/usr/share/terminfo/v/vt300-w
/usr/share/terminfo/v/vt300-w-nam
/usr/share/terminfo/v/vt330
/usr/share/terminfo/v/vt400-24
/usr/share/terminfo/v/vt61.5
/usr/share/terminfo/v/vtnt
/usr/share/terminfo/v/vv100
/usr/share/terminfo/w/wren
/usr/share/terminfo/w/wrenw
/usr/share/terminfo/w/wy-75ap
/usr/share/terminfo/w/wy-99fgt
/usr/share/terminfo/w/wy-99fgta
/usr/share/terminfo/w/wy120-wvb
/usr/share/terminfo/w/wy150
/usr/share/terminfo/w/wy150-25
/usr/share/terminfo/w/wy150-25-w
/usr/share/terminfo/w/wy150-vb
/usr/share/terminfo/w/wy150-w
/usr/share/terminfo/w/wy150-w-vb
/usr/share/terminfo/w/wy160-wvb
/usr/share/terminfo/w/wy325-42wvb
/usr/share/terminfo/w/wy325-43wvb
/usr/share/terminfo/w/wy325-80
/usr/share/terminfo/w/wy325-wvb
/usr/share/terminfo/w/wy325w-24
/usr/share/terminfo/w/wy370-101k
/usr/share/terminfo/w/wy60-316X
/usr/share/terminfo/w/wy60-AT
/usr/share/terminfo/w/wy60-PC
/usr/share/terminfo/w/wy60-wvb
/usr/share/terminfo/w/wy99fgt
/usr/share/terminfo/w/wy99fgta
/usr/share/terminfo/w/wy99gt-wvb
/usr/share/terminfo/w/wyse-325
/usr/share/terminfo/w/wyse-75ap
/usr/share/terminfo/w/wyse120
/usr/share/terminfo/w/wyse120-25
/usr/share/terminfo/w/wyse120-25-w
/usr/share/terminfo/w/wyse120-vb
/usr/share/terminfo/w/wyse120-w
/usr/share/terminfo/w/wyse120-wvb
/usr/share/terminfo/w/wyse150
/usr/share/terminfo/w/wyse150-25
/usr/share/terminfo/w/wyse150-25-w
/usr/share/terminfo/w/wyse150-vb
/usr/share/terminfo/w/wyse150-w
/usr/share/terminfo/w/wyse150-w-vb
/usr/share/terminfo/w/wyse160
/usr/share/terminfo/w/wyse160-25
/usr/share/terminfo/w/wyse160-25-w
/usr/share/terminfo/w/wyse160-42
/usr/share/terminfo/w/wyse160-42-w
/usr/share/terminfo/w/wyse160-43
/usr/share/terminfo/w/wyse160-43-w
/usr/share/terminfo/w/wyse160-vb
/usr/share/terminfo/w/wyse160-w
/usr/share/terminfo/w/wyse160-wvb
/usr/share/terminfo/w/wyse185
/usr/share/terminfo/w/wyse185-24
/usr/share/terminfo/w/wyse185-vb
/usr/share/terminfo/w/wyse185-w
/usr/share/terminfo/w/wyse185-wvb
/usr/share/terminfo/w/wyse30
/usr/share/terminfo/w/wyse30-mc
/usr/share/terminfo/w/wyse30-vb
/usr/share/terminfo/w/wyse325
/usr/share/terminfo/w/wyse325-25
/usr/share/terminfo/w/wyse325-25w
/usr/share/terminfo/w/wyse325-42
/usr/share/terminfo/w/wyse325-42w
/usr/share/terminfo/w/wyse325-43
/usr/share/terminfo/w/wyse325-43w
/usr/share/terminfo/w/wyse325-vb
/usr/share/terminfo/w/wyse325-w
/usr/share/terminfo/w/wyse325-wvb
/usr/share/terminfo/w/wyse350
/usr/share/terminfo/w/wyse350-vb
/usr/share/terminfo/w/wyse350-w
/usr/share/terminfo/w/wyse350-wvb
/usr/share/terminfo/w/wyse370
/usr/share/terminfo/w/wyse50
/usr/share/terminfo/w/wyse50-mc
/usr/share/terminfo/w/wyse50-vb
/usr/share/terminfo/w/wyse50-w
/usr/share/terminfo/w/wyse50-wvb
/usr/share/terminfo/w/wyse520
/usr/share/terminfo/w/wyse520-24
/usr/share/terminfo/w/wyse520-36
/usr/share/terminfo/w/wyse520-36pc
/usr/share/terminfo/w/wyse520-36w
/usr/share/terminfo/w/wyse520-36wpc
/usr/share/terminfo/w/wyse520-48
/usr/share/terminfo/w/wyse520-48pc
/usr/share/terminfo/w/wyse520-48w
/usr/share/terminfo/w/wyse520-48wpc
/usr/share/terminfo/w/wyse520-epc
/usr/share/terminfo/w/wyse520-epc-w
/usr/share/terminfo/w/wyse520-p-wvb
/usr/share/terminfo/w/wyse520-pc-24
/usr/share/terminfo/w/wyse520-pc-vb
/usr/share/terminfo/w/wyse520-vb
/usr/share/terminfo/w/wyse520-w
/usr/share/terminfo/w/wyse520-wvb
/usr/share/terminfo/w/wyse60
/usr/share/terminfo/w/wyse60-25
/usr/share/terminfo/w/wyse60-25-w
/usr/share/terminfo/w/wyse60-316X
/usr/share/terminfo/w/wyse60-42
/usr/share/terminfo/w/wyse60-42-w
/usr/share/terminfo/w/wyse60-43
/usr/share/terminfo/w/wyse60-43-w
/usr/share/terminfo/w/wyse60-AT
/usr/share/terminfo/w/wyse60-PC
/usr/share/terminfo/w/wyse60-vb
/usr/share/terminfo/w/wyse60-w
/usr/share/terminfo/w/wyse60-wvb
/usr/share/terminfo/w/wyse75
/usr/share/terminfo/w/wyse75-mc
/usr/share/terminfo/w/wyse75-vb
/usr/share/terminfo/w/wyse75-w
/usr/share/terminfo/w/wyse75-wvb
/usr/share/terminfo/w/wyse75ap
/usr/share/terminfo/w/wyse85
/usr/share/terminfo/w/wyse85-8bit
/usr/share/terminfo/w/wyse85-vb
/usr/share/terminfo/w/wyse85-w
/usr/share/terminfo/w/wyse85-wvb
/usr/share/terminfo/w/wyse99gt
/usr/share/terminfo/w/wyse99gt-25
/usr/share/terminfo/w/wyse99gt-25-w
/usr/share/terminfo/w/wyse99gt-vb
/usr/share/terminfo/w/wyse99gt-w
/usr/share/terminfo/w/wyse99gt-wvb
/usr/share/terminfo/x/x1700
/usr/share/terminfo/x/x1700-lm
/usr/share/terminfo/x/x1720
/usr/share/terminfo/x/x1750
/usr/share/terminfo/x/x68k-ite
/usr/share/terminfo/x/x820
/usr/share/terminfo/x/xdku
/usr/share/terminfo/x/xenix
/usr/share/terminfo/x/xerox
/usr/share/terminfo/x/xerox-lm
/usr/share/terminfo/x/xl83
/usr/share/terminfo/x/xterm-color
/usr/share/terminfo/x/xterm-r6
/usr/share/terminfo/x/xterm.js
/usr/share/terminfo/x/xterms
/usr/share/terminfo/x/xwsh
/usr/share/terminfo/z/z-100
/usr/share/terminfo/z/z-100bw
/usr/share/terminfo/z/z110
/usr/share/terminfo/z/z110bw
/usr/share/terminfo/z/z19
/usr/share/terminfo/z/z29a-kc-bc
/usr/share/terminfo/z/z29b
/usr/share/terminfo/z/z30
/usr/share/terminfo/z/z39a
/usr/share/terminfo/z/z50
/usr/share/terminfo/z/z8001
/usr/share/terminfo/z/zen8001
/usr/share/terminfo/z/zenith
/usr/share/terminfo/z/zenith29
/usr/share/terminfo/z/zenith39-a
/usr/share/terminfo/z/zenith39-ansi
/usr/share/terminfo/z/zt-1
/usr/share/terminfo/z/ztx-1-a
/usr/share/terminfo/z/ztx11
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           """
Package resource API
--------------------

A resource is a logical file contained within a package, or a logical
subdirectory thereof.  The package resource API expects resource names
to have their path parts separated with ``/``, *not* whatever the local
path separator is.  Do not use os.path operations to manipulate resource
names being passed into the API.

The package resource API is designed to work with normal filesystem packages,
.egg files, and unpacked .egg files.  It can also work in a limited way with
.zip files and with custom PEP 302 loaders that support the ``get_data()``
method.
"""

import sys
import os
import io
import time
import re
import types
import zipfile
import zipimport
import warnings
import stat
import functools
import pkgutil
import operator
import platform
import collections
import plistlib
import email.parser
import errno
import tempfile
import textwrap
import inspect
import ntpath
import posixpath
import importlib
from pkgutil import get_importer

try:
    import _imp
except ImportError:
    # Python 3.2 compatibility
    import imp as _imp

try:
    FileExistsError
except NameError:
    FileExistsError = OSError

# capture these to bypass sandboxing
from os import utime

try:
    from os import mkdir, rename, unlink

    WRITE_SUPPORT = True
except ImportError:
    # no write support, probably under GAE
    WRITE_SUPPORT = False

from os import open as os_open
from os.path import isdir, split

try:
    import importlib.machinery as importlib_machinery

    # access attribute to force import under delayed import mechanisms.
    importlib_machinery.__name__
except ImportError:
    importlib_machinery = None

from pkg_resources.extern.jaraco.text import (
    yield_lines,
    drop_comment,
    join_continuation,
)

from pkg_resources.extern import platformdirs
from pkg_resources.extern import packaging

__import__('pkg_resources.extern.packaging.version')
__import__('pkg_resources.extern.packaging.specifiers')
__import__('pkg_resources.extern.packaging.requirements')
__import__('pkg_resources.extern.packaging.markers')
__import__('pkg_resources.extern.packaging.utils')

if sys.version_info < (3, 5):
    raise RuntimeError("Python 3.5 or later is required")

# declare some globals that will be defined later to
# satisfy the linters.
require = None
working_set = None
add_activation_listener = None
resources_stream = None
cleanup_resources = None
resource_dir = None
resource_stream = None
set_extraction_path = None
resource_isdir = None
resource_string = None
iter_entry_points = None
resource_listdir = None
resource_filename = None
resource_exists = None
_distribution_finders = None
_namespace_handlers = None
_namespace_packages = None


class PEP440Warning(RuntimeWarning):
    """
    Used when there is an issue with a version or specifier not complying with
    PEP 440.
    """


parse_version = packaging.version.Version


_state_vars = {}


def _declare_state(vartype, **kw):
    globals().update(kw)
    _state_vars.update(dict.fromkeys(kw, vartype))


def __getstate__():
    state = {}
    g = globals()
    for k, v in _state_vars.items():
        state[k] = g['_sget_' + v](g[k])
    return state


def __setstate__(state):
    g = globals()
    for k, v in state.items():
        g['_sset_' + _state_vars[k]](k, g[k], v)
    return state


def _sget_dict(val):
    return val.copy()


def _sset_dict(key, ob, state):
    ob.clear()
    ob.update(state)


def _sget_object(val):
    return val.__getstate__()


def _sset_object(key, ob, state):
    ob.__setstate__(state)


_sget_none = _sset_none = lambda *args: None


def get_supported_platform():
    """Return this platform's maximum compatible version.

    distutils.util.get_platform() normally reports the minimum version
    of macOS that would be required to *use* extensions produced by
    distutils.  But what we want when checking compatibility is to know the
    version of macOS that we are *running*.  To allow usage of packages that
    explicitly require a newer version of macOS, we must also know the
    current version of the OS.

    If this condition occurs for any other platform with a version in its
    platform strings, this function should be extended accordingly.
    """
    plat = get_build_platform()
    m = macosVersionString.match(plat)
    if m is not None and sys.platform == "darwin":
        try:
            plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
        except ValueError:
            # not macOS
            pass
    return plat


__all__ = [
    # Basic resource access and distribution/entry point discovery
    'require',
    'run_script',
    'get_provider',
    'get_distribution',
    'load_entry_point',
    'get_entry_map',
    'get_entry_info',
    'iter_entry_points',
    'resource_string',
    'resource_stream',
    'resource_filename',
    'resource_listdir',
    'resource_exists',
    'resource_isdir',
    # Environmental control
    'declare_namespace',
    'working_set',
    'add_activation_listener',
    'find_distributions',
    'set_extraction_path',
    'cleanup_resources',
    'get_default_cache',
    # Primary implementation classes
    'Environment',
    'WorkingSet',
    'ResourceManager',
    'Distribution',
    'Requirement',
    'EntryPoint',
    # Exceptions
    'ResolutionError',
    'VersionConflict',
    'DistributionNotFound',
    'UnknownExtra',
    'ExtractionError',
    # Warnings
    'PEP440Warning',
    # Parsing functions and string utilities
    'parse_requirements',
    'parse_version',
    'safe_name',
    'safe_version',
    'get_platform',
    'compatible_platforms',
    'yield_lines',
    'split_sections',
    'safe_extra',
    'to_filename',
    'invalid_marker',
    'evaluate_marker',
    # filesystem utilities
    'ensure_directory',
    'normalize_path',
    # Distribution "precedence" constants
    'EGG_DIST',
    'BINARY_DIST',
    'SOURCE_DIST',
    'CHECKOUT_DIST',
    'DEVELOP_DIST',
    # "Provider" interfaces, implementations, and registration/lookup APIs
    'IMetadataProvider',
    'IResourceProvider',
    'FileMetadata',
    'PathMetadata',
    'EggMetadata',
    'EmptyProvider',
    'empty_provider',
    'NullProvider',
    'EggProvider',
    'DefaultProvider',
    'ZipProvider',
    'register_finder',
    'register_namespace_handler',
    'register_loader_type',
    'fixup_namespace_packages',
    'get_importer',
    # Warnings
    'PkgResourcesDeprecationWarning',
    # Deprecated/backward compatibility only
    'run_main',
    'AvailableDistributions',
]


class ResolutionError(Exception):
    """Abstract base for dependency resolution errors"""

    def __repr__(self):
        return self.__class__.__name__ + repr(self.args)


class VersionConflict(ResolutionError):
    """
    An already-installed version conflicts with the requested version.

    Should be initialized with the installed Distribution and the requested
    Requirement.
    """

    _template = "{self.dist} is installed but {self.req} is required"

    @property
    def dist(self):
        return self.args[0]

    @property
    def req(self):
        return self.args[1]

    def report(self):
        return self._template.format(**locals())

    def with_context(self, required_by):
        """
        If required_by is non-empty, return a version of self that is a
        ContextualVersionConflict.
        """
        if not required_by:
            return self
        args = self.args + (required_by,)
        return ContextualVersionConflict(*args)


class ContextualVersionConflict(VersionConflict):
    """
    A VersionConflict that accepts a third parameter, the set of the
    requirements that required the installed Distribution.
    """

    _template = VersionConflict._template + ' by {self.required_by}'

    @property
    def required_by(self):
        return self.args[2]


class DistributionNotFound(ResolutionError):
    """A requested distribution was not found"""

    _template = (
        "The '{self.req}' distribution was not found "
        "and is required by {self.requirers_str}"
    )

    @property
    def req(self):
        return self.args[0]

    @property
    def requirers(self):
        return self.args[1]

    @property
    def requirers_str(self):
        if not self.requirers:
            return 'the application'
        return ', '.join(self.requirers)

    def report(self):
        return self._template.format(**locals())

    def __str__(self):
        return self.report()


class UnknownExtra(ResolutionError):
    """Distribution doesn't have an "extra feature" of the given name"""


_provider_factories = {}

PY_MAJOR = '{}.{}'.format(*sys.version_info)
EGG_DIST = 3
BINARY_DIST = 2
SOURCE_DIST = 1
CHECKOUT_DIST = 0
DEVELOP_DIST = -1


def register_loader_type(loader_type, provider_factory):
    """Register `provider_factory` to make providers for `loader_type`

    `loader_type` is the type or class of a PEP 302 ``module.__loader__``,
    and `provider_factory` is a function that, passed a *module* object,
    returns an ``IResourceProvider`` for that module.
    """
    _provider_factories[loader_type] = provider_factory


def get_provider(moduleOrReq):
    """Return an IResourceProvider for the named module or requirement"""
    if isinstance(moduleOrReq, Requirement):
        return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
    try:
        module = sys.modules[moduleOrReq]
    except KeyError:
        __import__(moduleOrReq)
        module = sys.modules[moduleOrReq]
    loader = getattr(module, '__loader__', None)
    return _find_adapter(_provider_factories, loader)(module)


def _macos_vers(_cache=[]):
    if not _cache:
        version = platform.mac_ver()[0]
        # fallback for MacPorts
        if version == '':
            plist = '/System/Library/CoreServices/SystemVersion.plist'
            if os.path.exists(plist):
                if hasattr(plistlib, 'readPlist'):
                    plist_content = plistlib.readPlist(plist)
                    if 'ProductVersion' in plist_content:
                        version = plist_content['ProductVersion']

        _cache.append(version.split('.'))
    return _cache[0]


def _macos_arch(machine):
    return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)


def get_build_platform():
    """Return this platform's string for platform-specific distributions

    XXX Currently this is the same as ``distutils.util.get_platform()``, but it
    needs some hacks for Linux and macOS.
    """
    from sysconfig import get_platform

    plat = get_platform()
    if sys.platform == "darwin" and not plat.startswith('macosx-'):
        try:
            version = _macos_vers()
            machine = os.uname()[4].replace(" ", "_")
            return "macosx-%d.%d-%s" % (
                int(version[0]),
                int(version[1]),
                _macos_arch(machine),
            )
        except ValueError:
            # if someone is running a non-Mac darwin system, this will fall
            # through to the default implementation
            pass
    return plat


macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")
darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
# XXX backward compat
get_platform = get_build_platform


def compatible_platforms(provided, required):
    """Can code for the `provided` platform run on the `required` platform?

    Returns true if either platform is ``None``, or the platforms are equal.

    XXX Needs compatibility checks for Linux and other unixy OSes.
    """
    if provided is None or required is None or provided == required:
        # easy case
        return True

    # macOS special cases
    reqMac = macosVersionString.match(required)
    if reqMac:
        provMac = macosVersionString.match(provided)

        # is this a Mac package?
        if not provMac:
            # this is backwards compatibility for packages built before
            # setuptools 0.6. All packages built after this point will
            # use the new macOS designation.
            provDarwin = darwinVersionString.match(provided)
            if provDarwin:
                dversion = int(provDarwin.group(1))
                macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
                if (
                    dversion == 7
                    and macosversion >= "10.3"
                    or dversion == 8
                    and macosversion >= "10.4"
                ):
                    return True
            # egg isn't macOS or legacy darwin
            return False

        # are they the same major version and machine type?
        if provMac.group(1) != reqMac.group(1) or provMac.group(3) != reqMac.group(3):
            return False

        # is the required OS major update >= the provided one?
        if int(provMac.group(2)) > int(reqMac.group(2)):
            return False

        return True

    # XXX Linux and other platforms' special cases should go here
    return False


def run_script(dist_spec, script_name):
    """Locate distribution `dist_spec` and run its `script_name` script"""
    ns = sys._getframe(1).f_globals
    name = ns['__name__']
    ns.clear()
    ns['__name__'] = name
    require(dist_spec)[0].run_script(script_name, ns)


# backward compatibility
run_main = run_script


def get_distribution(dist):
    """Return a current distribution object for a Requirement or string"""
    if isinstance(dist, str):
        dist = Requirement.parse(dist)
    if isinstance(dist, Requirement):
        dist = get_provider(dist)
    if not isinstance(dist, Distribution):
        raise TypeError("Expected string, Requirement, or Distribution", dist)
    return dist


def load_entry_point(dist, group, name):
    """Return `name` entry point of `group` for `dist` or raise ImportError"""
    return get_distribution(dist).load_entry_point(group, name)


def get_entry_map(dist, group=None):
    """Return the entry point map for `group`, or the full entry map"""
    return get_distribution(dist).get_entry_map(group)


def get_entry_info(dist, group, name):
    """Return the EntryPoint object for `group`+`name`, or ``None``"""
    return get_distribution(dist).get_entry_info(group, name)


class IMetadataProvider:
    def has_metadata(name):
        """Does the package's distribution contain the named metadata?"""

    def get_metadata(name):
        """The named metadata resource as a string"""

    def get_metadata_lines(name):
        """Yield named metadata resource as list of non-blank non-comment lines

        Leading and trailing whitespace is stripped from each line, and lines
        with ``#`` as the first non-blank character are omitted."""

    def metadata_isdir(name):
        """Is the named metadata a directory?  (like ``os.path.isdir()``)"""

    def metadata_listdir(name):
        """List of metadata names in the directory (like ``os.listdir()``)"""

    def run_script(script_name, namespace):
        """Execute the named script in the supplied namespace dictionary"""


class IResourceProvider(IMetadataProvider):
    """An object that provides access to package resources"""

    def get_resource_filename(manager, resource_name):
        """Return a true filesystem path for `resource_name`

        `manager` must be an ``IResourceManager``"""

    def get_resource_stream(manager, resource_name):
        """Return a readable file-like object for `resource_name`

        `manager` must be an ``IResourceManager``"""

    def get_resource_string(manager, resource_name):
        """Return a string containing the contents of `resource_name`

        `manager` must be an ``IResourceManager``"""

    def has_resource(resource_name):
        """Does the package contain the named resource?"""

    def resource_isdir(resource_name):
        """Is the named resource a directory?  (like ``os.path.isdir()``)"""

    def resource_listdir(resource_name):
        """List of resource names in the directory (like ``os.listdir()``)"""


class WorkingSet:
    """A collection of active distributions on sys.path (or a similar list)"""

    def __init__(self, entries=None):
        """Create working set from list of path entries (default=sys.path)"""
        self.entries = []
        self.entry_keys = {}
        self.by_key = {}
        self.normalized_to_canonical_keys = {}
        self.callbacks = []

        if entries is None:
            entries = sys.path

        for entry in entries:
            self.add_entry(entry)

    @classmethod
    def _build_master(cls):
        """
        Prepare the master working set.
        """
        ws = cls()
        try:
            from __main__ import __requires__
        except ImportError:
            # The main program does not list any requirements
            return ws

        # ensure the requirements are met
        try:
            ws.require(__requires__)
        except VersionConflict:
            return cls._build_from_requirements(__requires__)

        return ws

    @classmethod
    def _build_from_requirements(cls, req_spec):
        """
        Build a working set from a requirement spec. Rewrites sys.path.
        """
        # try it without defaults already on sys.path
        # by starting with an empty path
        ws = cls([])
        reqs = parse_requirements(req_spec)
        dists = ws.resolve(reqs, Environment())
        for dist in dists:
            ws.add(dist)

        # add any missing entries from sys.path
        for entry in sys.path:
            if entry not in ws.entries:
                ws.add_entry(entry)

        # then copy back to sys.path
        sys.path[:] = ws.entries
        return ws

    def add_entry(self, entry):
        """Add a path item to ``.entries``, finding any distributions on it

        ``find_distributions(entry, True)`` is used to find distributions
        corresponding to the path entry, and they are added.  `entry` is
        always appended to ``.entries``, even if it is already present.
        (This is because ``sys.path`` can contain the same value more than
        once, and the ``.entries`` of the ``sys.path`` WorkingSet should always
        equal ``sys.path``.)
        """
        self.entry_keys.setdefault(entry, [])
        self.entries.append(entry)
        for dist in find_distributions(entry, True):
            self.add(dist, entry, False)

    def __contains__(self, dist):
        """True if `dist` is the active distribution for its project"""
        return self.by_key.get(dist.key) == dist

    def find(self, req):
        """Find a distribution matching requirement `req`

        If there is an active distribution for the requested project, this
        returns it as long as it meets the version requirement specified by
        `req`.  But, if there is an active distribution for the project and it
        does *not* meet the `req` requirement, ``VersionConflict`` is raised.
        If there is no active distribution for the requested project, ``None``
        is returned.
        """
        dist = self.by_key.get(req.key)

        if dist is None:
            canonical_key = self.normalized_to_canonical_keys.get(req.key)

            if canonical_key is not None:
                req.key = canonical_key
                dist = self.by_key.get(canonical_key)

        if dist is not None and dist not in req:
            # XXX add more info
            raise VersionConflict(dist, req)
        return dist

    def iter_entry_points(self, group, name=None):
        """Yield entry point objects from `group` matching `name`

        If `name` is None, yields all entry points in `group` from all
        distributions in the working set, otherwise only ones matching
        both `group` and `name` are yielded (in distribution order).
        """
        return (
            entry
            for dist in self
            for entry in dist.get_entry_map(group).values()
            if name is None or name == entry.name
        )

    def run_script(self, requires, script_name):
        """Locate distribution for `requires` and run `script_name` script"""
        ns = sys._getframe(1).f_globals
        name = ns['__name__']
        ns.clear()
        ns['__name__'] = name
        self.require(requires)[0].run_script(script_name, ns)

    def __iter__(self):
        """Yield distributions for non-duplicate projects in the working set

        The yield order is the order in which the items' path entries were
        added to the working set.
        """
        seen = {}
        for item in self.entries:
            if item not in self.entry_keys:
                # workaround a cache issue
                continue

            for key in self.entry_keys[item]:
                if key not in seen:
                    seen[key] = 1
                    yield self.by_key[key]

    def add(self, dist, entry=None, insert=True, replace=False):
        """Add `dist` to working set, associated with `entry`

        If `entry` is unspecified, it defaults to the ``.location`` of `dist`.
        On exit from this routine, `entry` is added to the end of the working
        set's ``.entries`` (if it wasn't already present).

        `dist` is only added to the working set if it's for a project that
        doesn't already have a distribution in the set, unless `replace=True`.
        If it's added, any callbacks registered with the ``subscribe()`` method
        will be called.
        """
        if insert:
            dist.insert_on(self.entries, entry, replace=replace)

        if entry is None:
            entry = dist.location
        keys = self.entry_keys.setdefault(entry, [])
        keys2 = self.entry_keys.setdefault(dist.location, [])
        if not replace and dist.key in self.by_key:
            # ignore hidden distros
            return

        self.by_key[dist.key] = dist
        normalized_name = packaging.utils.canonicalize_name(dist.key)
        self.normalized_to_canonical_keys[normalized_name] = dist.key
        if dist.key not in keys:
            keys.append(dist.key)
        if dist.key not in keys2:
            keys2.append(dist.key)
        self._added_new(dist)

    def resolve(
        self,
        requirements,
        env=None,
        installer=None,
        replace_conflicting=False,
        extras=None,
    ):
        """List all distributions needed to (recursively) meet `requirements`

        `requirements` must be a sequence of ``Requirement`` objects.  `env`,
        if supplied, should be an ``Environment`` instance.  If
        not supplied, it defaults to all distributions available within any
        entry or distribution in the working set.  `installer`, if supplied,
        will be invoked with each requirement that cannot be met by an
        already-installed distribution; it should return a ``Distribution`` or
        ``None``.

        Unless `replace_conflicting=True`, raises a VersionConflict exception
        if
        any requirements are found on the path that have the correct name but
        the wrong version.  Otherwise, if an `installer` is supplied it will be
        invoked to obtain the correct version of the requirement and activate
        it.

        `extras` is a list of the extras to be used with these requirements.
        This is important because extra requirements may look like `my_req;
        extra = "my_extra"`, which would otherwise be interpreted as a purely
        optional requirement.  Instead, we want to be able to assert that these
        requirements are truly required.
        """

        # set up the stack
        requirements = list(requirements)[::-1]
        # set of processed requirements
        processed = {}
        # key -> dist
        best = {}
        to_activate = []

        req_extras = _ReqExtras()

        # Mapping of requirement to set of distributions that required it;
        # useful for reporting info about conflicts.
        required_by = collections.defaultdict(set)

        while requirements:
            # process dependencies breadth-first
            req = requirements.pop(0)
            if req in processed:
                # Ignore cyclic or redundant dependencies
                continue

            if not req_extras.markers_pass(req, extras):
                continue

            dist = self._resolve_dist(
                req, best, replace_conflicting, env, installer, required_by, to_activate
            )

            # push the new requirements onto the stack
            new_requirements = dist.requires(req.extras)[::-1]
            requirements.extend(new_requirements)

            # Register the new requirements needed by req
            for new_requirement in new_requirements:
                required_by[new_requirement].add(req.project_name)
                req_extras[new_requirement] = req.extras

            processed[req] = True

        # return list of distros to activate
        return to_activate

    def _resolve_dist(
        self, req, best, replace_conflicting, env, installer, required_by, to_activate
    ):
        dist = best.get(req.key)
        if dist is None:
            # Find the best distribution and add it to the map
            dist = self.by_key.get(req.key)
            if dist is None or (dist not in req and replace_conflicting):
                ws = self
                if env is None:
                    if dist is None:
                        env = Environment(self.entries)
                    else:
                        # Use an empty environment and workingset to avoid
                        # any further conflicts with the conflicting
                        # distribution
                        env = Environment([])
                        ws = WorkingSet([])
                dist = best[req.key] = env.best_match(
                    req, ws, installer, replace_conflicting=replace_conflicting
                )
                if dist is None:
                    requirers = required_by.get(req, None)
                    raise DistributionNotFound(req, requirers)
            to_activate.append(dist)
        if dist not in req:
            # Oops, the "best" so far conflicts with a dependency
            dependent_req = required_by[req]
            raise VersionConflict(dist, req).with_context(dependent_req)
        return dist

    def find_plugins(self, plugin_env, full_env=None, installer=None, fallback=True):
        """Find all activatable distributions in `plugin_env`

        Example usage::

            distributions, errors = working_set.find_plugins(
                Environment(plugin_dirlist)
            )
            # add plugins+libs to sys.path
            map(working_set.add, distributions)
            # display errors
            print('Could not load', errors)

        The `plugin_env` should be an ``Environment`` instance that contains
        only distributions that are in the project's "plugin directory" or
        directories. The `full_env`, if supplied, should be an ``Environment``
        contains all currently-available distributions.  If `full_env` is not
        supplied, one is created automatically from the ``WorkingSet`` this
        method is called on, which will typically mean that every directory on
        ``sys.path`` will be scanned for distributions.

        `installer` is a standard installer callback as used by the
        ``resolve()`` method. The `fallback` flag indicates whether we should
        attempt to resolve older versions of a plugin if the newest version
        cannot be resolved.

        This method returns a 2-tuple: (`distributions`, `error_info`), where
        `distributions` is a list of the distributions found in `plugin_env`
        that were loadable, along with any other distributions that are needed
        to resolve their dependencies.  `error_info` is a dictionary mapping
        unloadable plugin distributions to an exception instance describing the
        error that occurred. Usually this will be a ``DistributionNotFound`` or
        ``VersionConflict`` instance.
        """

        plugin_projects = list(plugin_env)
        # scan project names in alphabetic order
        plugin_projects.sort()

        error_info = {}
        distributions = {}

        if full_env is None:
            env = Environment(self.entries)
            env += plugin_env
        else:
            env = full_env + plugin_env

        shadow_set = self.__class__([])
        # put all our entries in shadow_set
        list(map(shadow_set.add, self))

        for project_name in plugin_projects:

            for dist in plugin_env[project_name]:

                req = [dist.as_requirement()]

                try:
                    resolvees = shadow_set.resolve(req, env, installer)

                except ResolutionError as v:
                    # save error info
                    error_info[dist] = v
                    if fallback:
                        # try the next older version of project
                        continue
                    else:
                        # give up on this project, keep going
                        break

                else:
                    list(map(shadow_set.add, resolvees))
                    distributions.update(dict.fromkeys(resolvees))

                    # success, no need to try any more versions of this project
                    break

        distributions = list(distributions)
        distributions.sort()

        return distributions, error_info

    def require(self, *requirements):
        """Ensure that distributions matching `requirements` are activated

        `requirements` must be a string or a (possibly-nested) sequence
        thereof, specifying the distributions and versions required.  The
        return value is a sequence of the distributions that needed to be
        activated to fulfill the requirements; all relevant distributions are
        included, even if they were already activated in this working set.
        """
        needed = self.resolve(parse_requirements(requirements))

        for dist in needed:
            self.add(dist)

        return needed

    def subscribe(self, callback, existing=True):
        """Invoke `callback` for all distributions

        If `existing=True` (default),
        call on all existing ones, as well.
        """
        if callback in self.callbacks:
            return
        self.callbacks.append(callback)
        if not existing:
            return
        for dist in self:
            callback(dist)

    def _added_new(self, dist):
        for callback in self.callbacks:
            callback(dist)

    def __getstate__(self):
        return (
            self.entries[:],
            self.entry_keys.copy(),
            self.by_key.copy(),
            self.normalized_to_canonical_keys.copy(),
            self.callbacks[:],
        )

    def __setstate__(self, e_k_b_n_c):
        entries, keys, by_key, normalized_to_canonical_keys, callbacks = e_k_b_n_c
        self.entries = entries[:]
        self.entry_keys = keys.copy()
        self.by_key = by_key.copy()
        self.normalized_to_canonical_keys = normalized_to_canonical_keys.copy()
        self.callbacks = callbacks[:]


class _ReqExtras(dict):
    """
    Map each requirement to the extras that demanded it.
    """

    def markers_pass(self, req, extras=None):
        """
        Evaluate markers for req against each extra that
        demanded it.

        Return False if the req has a marker and fails
        evaluation. Otherwise, return True.
        """
        extra_evals = (
            req.marker.evaluate({'extra': extra})
            for extra in self.get(req, ()) + (extras or (None,))
        )
        return not req.marker or any(extra_evals)


class Environment:
    """Searchable snapshot of distributions on a search path"""

    def __init__(
        self, search_path=None, platform=get_supported_platform(), python=PY_MAJOR
    ):
        """Snapshot distributions available on a search path

        Any distributions found on `search_path` are added to the environment.
        `search_path` should be a sequence of ``sys.path`` items.  If not
        supplied, ``sys.path`` is used.

        `platform` is an optional string specifying the name of the platform
        that platform-specific distributions must be compatible with.  If
        unspecified, it defaults to the current platform.  `python` is an
        optional string naming the desired version of Python (e.g. ``'3.6'``);
        it defaults to the current version.

        You may explicitly set `platform` (and/or `python`) to ``None`` if you
        wish to map *all* distributions, not just those compatible with the
        running platform or Python version.
        """
        self._distmap = {}
        self.platform = platform
        self.python = python
        self.scan(search_path)

    def can_add(self, dist):
        """Is distribution `dist` acceptable for this environment?

        The distribution must match the platform and python version
        requirements specified when this environment was created, or False
        is returned.
        """
        py_compat = (
            self.python is None
            or dist.py_version is None
            or dist.py_version == self.python
        )
        return py_compat and compatible_platforms(dist.platform, self.platform)

    def remove(self, dist):
        """Remove `dist` from the environment"""
        self._distmap[dist.key].remove(dist)

    def scan(self, search_path=None):
        """Scan `search_path` for distributions usable in this environment

        Any distributions found are added to the environment.
        `search_path` should be a sequence of ``sys.path`` items.  If not
        supplied, ``sys.path`` is used.  Only distributions conforming to
        the platform/python version defined at initialization are added.
        """
        if search_path is None:
            search_path = sys.path

        for item in search_path:
            for dist in find_distributions(item):
                self.add(dist)

    def __getitem__(self, project_name):
        """Return a newest-to-oldest list of distributions for `project_name`

        Uses case-insensitive `project_name` comparison, assuming all the
        project's distributions use their project's name converted to all
        lowercase as their key.

        """
        distribution_key = project_name.lower()
        return self._distmap.get(distribution_key, [])

    def add(self, dist):
        """Add `dist` if we ``can_add()`` it and it has not already been added"""
        if self.can_add(dist) and dist.has_version():
            dists = self._distmap.setdefault(dist.key, [])
            if dist not in dists:
                dists.append(dist)
                dists.sort(key=operator.attrgetter('hashcmp'), reverse=True)

    def best_match(self, req, working_set, installer=None, replace_conflicting=False):
        """Find distribution best matching `req` and usable on `working_set`

        This calls the ``find(req)`` method of the `working_set` to see if a
        suitable distribution is already active.  (This may raise
        ``VersionConflict`` if an unsuitable version of the project is already
        active in the specified `working_set`.)  If a suitable distribution
        isn't active, this method returns the newest distribution in the
        environment that meets the ``Requirement`` in `req`.  If no suitable
        distribution is found, and `installer` is supplied, then the result of
        calling the environment's ``obtain(req, installer)`` method will be
        returned.
        """
        try:
            dist = working_set.find(req)
        except VersionConflict:
            if not replace_conflicting:
                raise
            dist = None
        if dist is not None:
            return dist
        for dist in self[req.key]:
            if dist in req:
                return dist
        # try to download/install
        return self.obtain(req, installer)

    def obtain(self, requirement, installer=None):
        """Obtain a distribution matching `requirement` (e.g. via download)

        Obtain a distro that matches requirement (e.g. via download).  In the
        base ``Environment`` class, this routine just returns
        ``installer(requirement)``, unless `installer` is None, in which case
        None is returned instead.  This method is a hook that allows subclasses
        to attempt other ways of obtaining a distribution before falling back
        to the `installer` argument."""
        if installer is not None:
            return installer(requirement)

    def __iter__(self):
        """Yield the unique project names of the available distributions"""
        for key in self._distmap.keys():
            if self[key]:
                yield key

    def __iadd__(self, other):
        """In-place addition of a distribution or environment"""
        if isinstance(other, Distribution):
            self.add(other)
        elif isinstance(other, Environment):
            for project in other:
                for dist in other[project]:
                    self.add(dist)
        else:
            raise TypeError("Can't add %r to environment" % (other,))
        return self

    def __add__(self, other):
        """Add an environment or distribution to an environment"""
        new = self.__class__([], platform=None, python=None)
        for env in self, other:
            new += env
        return new


# XXX backward compatibility
AvailableDistributions = Environment


class ExtractionError(RuntimeError):
    """An error occurred extracting a resource

    The following attributes are available from instances of this exception:

    manager
        The resource manager that raised this exception

    cache_path
        The base directory for resource extraction

    original_error
        The exception instance that caused extraction to fail
    """


class ResourceManager:
    """Manage resource extraction and packages"""

    extraction_path = None

    def __init__(self):
        self.cached_files = {}

    def resource_exists(self, package_or_requirement, resource_name):
        """Does the named resource exist?"""
        return get_provider(package_or_requirement).has_resource(resource_name)

    def resource_isdir(self, package_or_requirement, resource_name):
        """Is the named resource an existing directory?"""
        return get_provider(package_or_requirement).resource_isdir(resource_name)

    def resource_filename(self, package_or_requirement, resource_name):
        """Return a true filesystem path for specified resource"""
        return get_provider(package_or_requirement).get_resource_filename(
            self, resource_name
        )

    def resource_stream(self, package_or_requirement, resource_name):
        """Return a readable file-like object for specified resource"""
        return get_provider(package_or_requirement).get_resource_stream(
            self, resource_name
        )

    def resource_string(self, package_or_requirement, resource_name):
        """Return specified resource as a string"""
        return get_provider(package_or_requirement).get_resource_string(
            self, resource_name
        )

    def resource_listdir(self, package_or_requirement, resource_name):
        """List the contents of the named resource directory"""
        return get_provider(package_or_requirement).resource_listdir(resource_name)

    def extraction_error(self):
        """Give an error message for problems extracting file(s)"""

        old_exc = sys.exc_info()[1]
        cache_path = self.extraction_path or get_default_cache()

        tmpl = textwrap.dedent(
            """
            Can't extract file(s) to egg cache

            The following error occurred while trying to extract file(s)
            to the Python egg cache:

              {old_exc}

            The Python egg cache directory is currently set to:

              {cache_path}

            Perhaps your account does not have write access to this directory?
            You can change the cache directory by setting the PYTHON_EGG_CACHE
            environment variable to point to an accessible directory.
            """
        ).lstrip()
        err = ExtractionError(tmpl.format(**locals()))
        err.manager = self
        err.cache_path = cache_path
        err.original_error = old_exc
        raise err

    def get_cache_path(self, archive_name, names=()):
        """Return absolute location in cache for `archive_name` and `names`

        The parent directory of the resulting path will be created if it does
        not already exist.  `archive_name` should be the base filename of the
        enclosing egg (which may not be the name of the enclosing zipfile!),
        including its ".egg" extension.  `names`, if provided, should be a
        sequence of path name parts "under" the egg's extraction location.

        This method should only be called by resource providers that need to
        obtain an extraction location, and only for names they intend to
        extract, as it tracks the generated names for possible cleanup later.
        """
        extract_path = self.extraction_path or get_default_cache()
        target_path = os.path.join(extract_path, archive_name + '-tmp', *names)
        try:
            _bypass_ensure_directory(target_path)
        except Exception:
            self.extraction_error()

        self._warn_unsafe_extraction_path(extract_path)

        self.cached_files[target_path] = 1
        return target_path

    @staticmethod
    def _warn_unsafe_extraction_path(path):
        """
        If the default extraction path is overridden and set to an insecure
        location, such as /tmp, it opens up an opportunity for an attacker to
        replace an extracted file with an unauthorized payload. Warn the user
        if a known insecure location is used.

        See Distribute #375 for more details.
        """
        if os.name == 'nt' and not path.startswith(os.environ['windir']):
            # On Windows, permissions are generally restrictive by default
            #  and temp directories are not writable by other users, so
            #  bypass the warning.
            return
        mode = os.stat(path).st_mode
        if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
            msg = (
                "Extraction path is writable by group/others "
                "and vulnerable to attack when "
                "used with get_resource_filename ({path}). "
                "Consider a more secure "
                "location (set with .set_extraction_path or the "
                "PYTHON_EGG_CACHE environment variable)."
            ).format(**locals())
            warnings.warn(msg, UserWarning)

    def postprocess(self, tempname, filename):
        """Perform any platform-specific postprocessing of `tempname`

        This is where Mac header rewrites should be done; other platforms don't
        have anything special they should do.

        Resource providers should call this method ONLY after successfully
        extracting a compressed resource.  They must NOT call it on resources
        that are already in the filesystem.

        `tempname` is the current (temporary) name of the file, and `filename`
        is the name it will be renamed to by the caller after this routine
        returns.
        """

        if os.name == 'posix':
            # Make the resource executable
            mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777
            os.chmod(tempname, mode)

    def set_extraction_path(self, path):
        """Set the base path where resources will be extracted to, if needed.

        If you do not call this routine before any extractions take place, the
        path defaults to the return value of ``get_default_cache()``.  (Which
        is based on the ``PYTHON_EGG_CACHE`` environment variable, with various
        platform-specific fallbacks.  See that routine's documentation for more
        details.)

        Resources are extracted to subdirectories of this path based upon
        information given by the ``IResourceProvider``.  You may set this to a
        temporary directory, but then you must call ``cleanup_resources()`` to
        delete the extracted files when done.  There is no guarantee that
        ``cleanup_resources()`` will be able to remove all extracted files.

        (Note: you may not change the extraction path for a given resource
        manager once resources have been extracted, unless you first call
        ``cleanup_resources()``.)
        """
        if self.cached_files:
            raise ValueError("Can't change extraction path, files already extracted")

        self.extraction_path = path

    def cleanup_resources(self, force=False):
        """
        Delete all extracted resource files and directories, returning a list
        of the file and directory names that could not be successfully removed.
        This function does not have any concurrency protection, so it should
        generally only be called when the extraction path is a temporary
        directory exclusive to a single process.  This method is not
        automatically called; you must call it explicitly or register it as an
        ``atexit`` function if you wish to ensure cleanup of a temporary
        directory used for extractions.
        """
        # XXX


def get_default_cache():
    """
    Return the ``PYTHON_EGG_CACHE`` environment variable
    or a platform-relevant user cache dir for an app
    named "Python-Eggs".
    """
    return os.environ.get('PYTHON_EGG_CACHE') or platformdirs.user_cache_dir(
        appname='Python-Eggs'
    )


def safe_name(name):
    """Convert an arbitrary string to a standard distribution name

    Any runs of non-alphanumeric/. characters are replaced with a single '-'.
    """
    return re.sub('[^A-Za-z0-9.]+', '-', name)


def safe_version(version):
    """
    Convert an arbitrary string to a standard version string
    """
    try:
        # normalize the version
        return str(packaging.version.Version(version))
    except packaging.version.InvalidVersion:
        version = version.replace(' ', '.')
        return re.sub('[^A-Za-z0-9.]+', '-', version)


def safe_extra(extra):
    """Convert an arbitrary string to a standard 'extra' name

    Any runs of non-alphanumeric characters are replaced with a single '_',
    and the result is always lowercased.
    """
    return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower()


def to_filename(name):
    """Convert a project or version name to its filename-escaped form

    Any '-' characters are currently replaced with '_'.
    """
    return name.replace('-', '_')


def invalid_marker(text):
    """
    Validate text as a PEP 508 environment marker; return an exception
    if invalid or False otherwise.
    """
    try:
        evaluate_marker(text)
    except SyntaxError as e:
        e.filename = None
        e.lineno = None
        return e
    return False


def evaluate_marker(text, extra=None):
    """
    Evaluate a PEP 508 environment marker.
    Return a boolean indicating the marker result in this environment.
    Raise SyntaxError if marker is invalid.

    This implementation uses the 'pyparsing' module.
    """
    try:
        marker = packaging.markers.Marker(text)
        return marker.evaluate()
    except packaging.markers.InvalidMarker as e:
        raise SyntaxError(e) from e


class NullProvider:
    """Try to implement resources and metadata for arbitrary PEP 302 loaders"""

    egg_name = None
    egg_info = None
    loader = None

    def __init__(self, module):
        self.loader = getattr(module, '__loader__', None)
        self.module_path = os.path.dirname(getattr(module, '__file__', ''))

    def get_resource_filename(self, manager, resource_name):
        return self._fn(self.module_path, resource_name)

    def get_resource_stream(self, manager, resource_name):
        return io.BytesIO(self.get_resource_string(manager, resource_name))

    def get_resource_string(self, manager, resource_name):
        return self._get(self._fn(self.module_path, resource_name))

    def has_resource(self, resource_name):
        return self._has(self._fn(self.module_path, resource_name))

    def _get_metadata_path(self, name):
        return self._fn(self.egg_info, name)

    def has_metadata(self, name):
        if not self.egg_info:
            return self.egg_info

        path = self._get_metadata_path(name)
        return self._has(path)

    def get_metadata(self, name):
        if not self.egg_info:
            return ""
        path = self._get_metadata_path(name)
        value = self._get(path)
        try:
            return value.decode('utf-8')
        except UnicodeDecodeError as exc:
            # Include the path in the error message to simplify
            # troubleshooting, and without changing the exception type.
            exc.reason += ' in {} file at path: {}'.format(name, path)
            raise

    def get_metadata_lines(self, name):
        return yield_lines(self.get_metadata(name))

    def resource_isdir(self, resource_name):
        return self._isdir(self._fn(self.module_path, resource_name))

    def metadata_isdir(self, name):
        return self.egg_info and self._isdir(self._fn(self.egg_info, name))

    def resource_listdir(self, resource_name):
        return self._listdir(self._fn(self.module_path, resource_name))

    def metadata_listdir(self, name):
        if self.egg_info:
            return self._listdir(self._fn(self.egg_info, name))
        return []

    def run_script(self, script_name, namespace):
        script = 'scripts/' + script_name
        if not self.has_metadata(script):
            raise ResolutionError(
                "Script {script!r} not found in metadata at {self.egg_info!r}".format(
                    **locals()
                ),
            )
        script_text = self.get_metadata(script).replace('\r\n', '\n')
        script_text = script_text.replace('\r', '\n')
        script_filename = self._fn(self.egg_info, script)
        namespace['__file__'] = script_filename
        if os.path.exists(script_filename):
            with open(script_filename) as fid:
                source = fid.read()
            code = compile(source, script_filename, 'exec')
            exec(code, namespace, namespace)
        else:
            from linecache import cache

            cache[script_filename] = (
                len(script_text),
                0,
                script_text.split('\n'),
                script_filename,
            )
            script_code = compile(script_text, script_filename, 'exec')
            exec(script_code, namespace, namespace)

    def _has(self, path):
        raise NotImplementedError(
            "Can't perform this operation for unregistered loader type"
        )

    def _isdir(self, path):
        raise NotImplementedError(
            "Can't perform this operation for unregistered loader type"
        )

    def _listdir(self, path):
        raise NotImplementedError(
            "Can't perform this operation for unregistered loader type"
        )

    def _fn(self, base, resource_name):
        self._validate_resource_path(resource_name)
        if resource_name:
            return os.path.join(base, *resource_name.split('/'))
        return base

    @staticmethod
    def _validate_resource_path(path):
        """
        Validate the resource paths according to the docs.
        https://setuptools.pypa.io/en/latest/pkg_resources.html#basic-resource-access

        >>> warned = getfixture('recwarn')
        >>> warnings.simplefilter('always')
        >>> vrp = NullProvider._validate_resource_path
        >>> vrp('foo/bar.txt')
        >>> bool(warned)
        False
        >>> vrp('../foo/bar.txt')
        >>> bool(warned)
        True
        >>> warned.clear()
        >>> vrp('/foo/bar.txt')
        >>> bool(warned)
        True
        >>> vrp('foo/../../bar.txt')
        >>> bool(warned)
        True
        >>> warned.clear()
        >>> vrp('foo/f../bar.txt')
        >>> bool(warned)
        False

        Windows path separators are straight-up disallowed.
        >>> vrp(r'\\foo/bar.txt')
        Traceback (most recent call last):
        ...
        ValueError: Use of .. or absolute path in a resource path \
is not allowed.

        >>> vrp(r'C:\\foo/bar.txt')
        Traceback (most recent call last):
        ...
        ValueError: Use of .. or absolute path in a resource path \
is not allowed.

        Blank values are allowed

        >>> vrp('')
        >>> bool(warned)
        False

        Non-string values are not.

        >>> vrp(None)
        Traceback (most recent call last):
        ...
        AttributeError: ...
        """
        invalid = (
            os.path.pardir in path.split(posixpath.sep)
            or posixpath.isabs(path)
            or ntpath.isabs(path)
        )
        if not invalid:
            return

        msg = "Use of .. or absolute path in a resource path is not allowed."

        # Aggressively disallow Windows absolute paths
        if ntpath.isabs(path) and not posixpath.isabs(path):
            raise ValueError(msg)

        # for compatibility, warn; in future
        # raise ValueError(msg)
        warnings.warn(
            msg[:-1] + " and will raise exceptions in a future release.",
            DeprecationWarning,
            stacklevel=4,
        )

    def _get(self, path):
        if hasattr(self.loader, 'get_data'):
            return self.loader.get_data(path)
        raise NotImplementedError(
            "Can't perform this operation for loaders without 'get_data()'"
        )


register_loader_type(object, NullProvider)


def _parents(path):
    """
    yield all parents of path including path
    """
    last = None
    while path != last:
        yield path
        last = path
        path, _ = os.path.split(path)


class EggProvider(NullProvider):
    """Provider based on a virtual filesystem"""

    def __init__(self, module):
        super().__init__(module)
        self._setup_prefix()

    def _setup_prefix(self):
        # Assume that metadata may be nested inside a "basket"
        # of multiple eggs and use module_path instead of .archive.
        eggs = filter(_is_egg_path, _parents(self.module_path))
        egg = next(eggs, None)
        egg and self._set_egg(egg)

    def _set_egg(self, path):
        self.egg_name = os.path.basename(path)
        self.egg_info = os.path.join(path, 'EGG-INFO')
        self.egg_root = path


class DefaultProvider(EggProvider):
    """Provides access to package resources in the filesystem"""

    def _has(self, path):
        return os.path.exists(path)

    def _isdir(self, path):
        return os.path.isdir(path)

    def _listdir(self, path):
        return os.listdir(path)

    def get_resource_stream(self, manager, resource_name):
        return open(self._fn(self.module_path, resource_name), 'rb')

    def _get(self, path):
        with open(path, 'rb') as stream:
            return stream.read()

    @classmethod
    def _register(cls):
        loader_names = (
            'SourceFileLoader',
            'SourcelessFileLoader',
        )
        for name in loader_names:
            loader_cls = getattr(importlib_machinery, name, type(None))
            register_loader_type(loader_cls, cls)


DefaultProvider._register()


class EmptyProvider(NullProvider):
    """Provider that returns nothing for all requests"""

    module_path = None

    _isdir = _has = lambda self, path: False

    def _get(self, path):
        return ''

    def _listdir(self, path):
        return []

    def __init__(self):
        pass


empty_provider = EmptyProvider()


class ZipManifests(dict):
    """
    zip manifest builder
    """

    @classmethod
    def build(cls, path):
        """
        Build a dictionary similar to the zipimport directory
        caches, except instead of tuples, store ZipInfo objects.

        Use a platform-specific path separator (os.sep) for the path keys
        for compatibility with pypy on Windows.
        """
        with zipfile.ZipFile(path) as zfile:
            items = (
                (
                    name.replace('/', os.sep),
                    zfile.getinfo(name),
                )
                for name in zfile.namelist()
            )
            return dict(items)

    load = build


class MemoizedZipManifests(ZipManifests):
    """
    Memoized zipfile manifests.
    """

    manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime')

    def load(self, path):
        """
        Load a manifest at path or return a suitable manifest already loaded.
        """
        path = os.path.normpath(path)
        mtime = os.stat(path).st_mtime

        if path not in self or self[path].mtime != mtime:
            manifest = self.build(path)
            self[path] = self.manifest_mod(manifest, mtime)

        return self[path].manifest


class ZipProvider(EggProvider):
    """Resource support for zips and eggs"""

    eagers = None
    _zip_manifests = MemoizedZipManifests()

    def __init__(self, module):
        super().__init__(module)
        self.zip_pre = self.loader.archive + os.sep

    def _zipinfo_name(self, fspath):
        # Convert a virtual filename (full path to file) into a zipfile subpath
        # usable with the zipimport directory cache for our target archive
        fspath = fspath.rstrip(os.sep)
        if fspath == self.loader.archive:
            return ''
        if fspath.startswith(self.zip_pre):
            return fspath[len(self.zip_pre) :]
        raise AssertionError("%s is not a subpath of %s" % (fspath, self.zip_pre))

    def _parts(self, zip_path):
        # Convert a zipfile subpath into an egg-relative path part list.
        # pseudo-fs path
        fspath = self.zip_pre + zip_path
        if fspath.startswith(self.egg_root + os.sep):
            return fspath[len(self.egg_root) + 1 :].split(os.sep)
        raise AssertionError("%s is not a subpath of %s" % (fspath, self.egg_root))

    @property
    def zipinfo(self):
        return self._zip_manifests.load(self.loader.archive)

    def get_resource_filename(self, manager, resource_name):
        if not self.egg_name:
            raise NotImplementedError(
                "resource_filename() only supported for .egg, not .zip"
            )
        # no need to lock for extraction, since we use temp names
        zip_path = self._resource_to_zip(resource_name)
        eagers = self._get_eager_resources()
        if '/'.join(self._parts(zip_path)) in eagers:
            for name in eagers:
                self._extract_resource(manager, self._eager_to_zip(name))
        return self._extract_resource(manager, zip_path)

    @staticmethod
    def _get_date_and_size(zip_stat):
        size = zip_stat.file_size
        # ymdhms+wday, yday, dst
        date_time = zip_stat.date_time + (0, 0, -1)
        # 1980 offset already done
        timestamp = time.mktime(date_time)
        return timestamp, size

    # FIXME: 'ZipProvider._extract_resource' is too complex (12)
    def _extract_resource(self, manager, zip_path):  # noqa: C901

        if zip_path in self._index():
            for name in self._index()[zip_path]:
                last = self._extract_resource(manager, os.path.join(zip_path, name))
            # return the extracted directory name
            return os.path.dirname(last)

        timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])

        if not WRITE_SUPPORT:
            raise IOError(
                '"os.rename" and "os.unlink" are not supported ' 'on this platform'
            )
        try:

            real_path = manager.get_cache_path(self.egg_name, self._parts(zip_path))

            if self._is_current(real_path, zip_path):
                return real_path

            outf, tmpnam = _mkstemp(
                ".$extract",
                dir=os.path.dirname(real_path),
            )
            os.write(outf, self.loader.get_data(zip_path))
            os.close(outf)
            utime(tmpnam, (timestamp, timestamp))
            manager.postprocess(tmpnam, real_path)

            try:
                rename(tmpnam, real_path)

            except os.error:
                if os.path.isfile(real_path):
                    if self._is_current(real_path, zip_path):
                        # the file became current since it was checked above,
                        #  so proceed.
                        return real_path
                    # Windows, del old file and retry
                    elif os.name == 'nt':
                        unlink(real_path)
                        rename(tmpnam, real_path)
                        return real_path
                raise

        except os.error:
            # report a user-friendly error
            manager.extraction_error()

        return real_path

    def _is_current(self, file_path, zip_path):
        """
        Return True if the file_path is current for this zip_path
        """
        timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
        if not os.path.isfile(file_path):
            return False
        stat = os.stat(file_path)
        if stat.st_size != size or stat.st_mtime != timestamp:
            return False
        # check that the contents match
        zip_contents = self.loader.get_data(zip_path)
        with open(file_path, 'rb') as f:
            file_contents = f.read()
        return zip_contents == file_contents

    def _get_eager_resources(self):
        if self.eagers is None:
            eagers = []
            for name in ('native_libs.txt', 'eager_resources.txt'):
                if self.has_metadata(name):
                    eagers.extend(self.get_metadata_lines(name))
            self.eagers = eagers
        return self.eagers

    def _index(self):
        try:
            return self._dirindex
        except AttributeError:
            ind = {}
            for path in self.zipinfo:
                parts = path.split(os.sep)
                while parts:
                    parent = os.sep.join(parts[:-1])
                    if parent in ind:
                        ind[parent].append(parts[-1])
                        break
                    else:
                        ind[parent] = [parts.pop()]
            self._dirindex = ind
            return ind

    def _has(self, fspath):
        zip_path = self._zipinfo_name(fspath)
        return zip_path in self.zipinfo or zip_path in self._index()

    def _isdir(self, fspath):
        return self._zipinfo_name(fspath) in self._index()

    def _listdir(self, fspath):
        return list(self._index().get(self._zipinfo_name(fspath), ()))

    def _eager_to_zip(self, resource_name):
        return self._zipinfo_name(self._fn(self.egg_root, resource_name))

    def _resource_to_zip(self, resource_name):
        return self._zipinfo_name(self._fn(self.module_path, resource_name))


register_loader_type(zipimport.zipimporter, ZipProvider)


class FileMetadata(EmptyProvider):
    """Metadata handler for standalone PKG-INFO files

    Usage::

        metadata = FileMetadata("/path/to/PKG-INFO")

    This provider rejects all data and metadata requests except for PKG-INFO,
    which is treated as existing, and will be the contents of the file at
    the provided location.
    """

    def __init__(self, path):
        self.path = path

    def _get_metadata_path(self, name):
        return self.path

    def has_metadata(self, name):
        return name == 'PKG-INFO' and os.path.isfile(self.path)

    def get_metadata(self, name):
        if name != 'PKG-INFO':
            raise KeyError("No metadata except PKG-INFO is available")

        with io.open(self.path, encoding='utf-8', errors="replace") as f:
            metadata = f.read()
        self._warn_on_replacement(metadata)
        return metadata

    def _warn_on_replacement(self, metadata):
        replacement_char = '�'
        if replacement_char in metadata:
            tmpl = "{self.path} could not be properly decoded in UTF-8"
            msg = tmpl.format(**locals())
            warnings.warn(msg)

    def get_metadata_lines(self, name):
        return yield_lines(self.get_metadata(name))


class PathMetadata(DefaultProvider):
    """Metadata provider for egg directories

    Usage::

        # Development eggs:

        egg_info = "/path/to/PackageName.egg-info"
        base_dir = os.path.dirname(egg_info)
        metadata = PathMetadata(base_dir, egg_info)
        dist_name = os.path.splitext(os.path.basename(egg_info))[0]
        dist = Distribution(basedir, project_name=dist_name, metadata=metadata)

        # Unpacked egg directories:

        egg_path = "/path/to/PackageName-ver-pyver-etc.egg"
        metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO'))
        dist = Distribution.from_filename(egg_path, metadata=metadata)
    """

    def __init__(self, path, egg_info):
        self.module_path = path
        self.egg_info = egg_info


class EggMetadata(ZipProvider):
    """Metadata provider for .egg files"""

    def __init__(self, importer):
        """Create a metadata provider from a zipimporter"""

        self.zip_pre = importer.archive + os.sep
        self.loader = importer
        if importer.prefix:
            self.module_path = os.path.join(importer.archive, importer.prefix)
        else:
            self.module_path = importer.archive
        self._setup_prefix()


_declare_state('dict', _distribution_finders={})


def register_finder(importer_type, distribution_finder):
    """Register `distribution_finder` to find distributions in sys.path items

    `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
    handler), and `distribution_finder` is a callable that, passed a path
    item and the importer instance, yields ``Distribution`` instances found on
    that path item.  See ``pkg_resources.find_on_path`` for an example."""
    _distribution_finders[importer_type] = distribution_finder


def find_distributions(path_item, only=False):
    """Yield distributions accessible via `path_item`"""
    importer = get_importer(path_item)
    finder = _find_adapter(_distribution_finders, importer)
    return finder(importer, path_item, only)


def find_eggs_in_zip(importer, path_item, only=False):
    """
    Find eggs in zip files; possibly multiple nested eggs.
    """
    if importer.archive.endswith('.whl'):
        # wheels are not supported with this finder
        # they don't have PKG-INFO metadata, and won't ever contain eggs
        return
    metadata = EggMetadata(importer)
    if metadata.has_metadata('PKG-INFO'):
        yield Distribution.from_filename(path_item, metadata=metadata)
    if only:
        # don't yield nested distros
        return
    for subitem in metadata.resource_listdir(''):
        if _is_egg_path(subitem):
            subpath = os.path.join(path_item, subitem)
            dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath)
            for dist in dists:
                yield dist
        elif subitem.lower().endswith(('.dist-info', '.egg-info')):
            subpath = os.path.join(path_item, subitem)
            submeta = EggMetadata(zipimport.zipimporter(subpath))
            submeta.egg_info = subpath
            yield Distribution.from_location(path_item, subitem, submeta)


register_finder(zipimport.zipimporter, find_eggs_in_zip)


def find_nothing(importer, path_item, only=False):
    return ()


register_finder(object, find_nothing)


def find_on_path(importer, path_item, only=False):
    """Yield distributions accessible on a sys.path directory"""
    path_item = _normalize_cached(path_item)

    if _is_unpacked_egg(path_item):
        yield Distribution.from_filename(
            path_item,
            metadata=PathMetadata(path_item, os.path.join(path_item, 'EGG-INFO')),
        )
        return

    entries = (os.path.join(path_item, child) for child in safe_listdir(path_item))

    # scan for .egg and .egg-info in directory
    for entry in sorted(entries):
        fullpath = os.path.join(path_item, entry)
        factory = dist_factory(path_item, entry, only)
        for dist in factory(fullpath):
            yield dist


def dist_factory(path_item, entry, only):
    """Return a dist_factory for the given entry."""
    lower = entry.lower()
    is_egg_info = lower.endswith('.egg-info')
    is_dist_info = lower.endswith('.dist-info') and os.path.isdir(
        os.path.join(path_item, entry)
    )
    is_meta = is_egg_info or is_dist_info
    return (
        distributions_from_metadata
        if is_meta
        else find_distributions
        if not only and _is_egg_path(entry)
        else resolve_egg_link
        if not only and lower.endswith('.egg-link')
        else NoDists()
    )


class NoDists:
    """
    >>> bool(NoDists())
    False

    >>> list(NoDists()('anything'))
    []
    """

    def __bool__(self):
        return False

    def __call__(self, fullpath):
        return iter(())


def safe_listdir(path):
    """
    Attempt to list contents of path, but suppress some exceptions.
    """
    try:
        return os.listdir(path)
    except (PermissionError, NotADirectoryError):
        pass
    except OSError as e:
        # Ignore the directory if does not exist, not a directory or
        # permission denied
        if e.errno not in (errno.ENOTDIR, errno.EACCES, errno.ENOENT):
            raise
    return ()


def distributions_from_metadata(path):
    root = os.path.dirname(path)
    if os.path.isdir(path):
        if len(os.listdir(path)) == 0:
            # empty metadata dir; skip
            return
        metadata = PathMetadata(root, path)
    else:
        metadata = FileMetadata(path)
    entry = os.path.basename(path)
    yield Distribution.from_location(
        root,
        entry,
        metadata,
        precedence=DEVELOP_DIST,
    )


def non_empty_lines(path):
    """
    Yield non-empty lines from file at path
    """
    with open(path) as f:
        for line in f:
            line = line.strip()
            if line:
                yield line


def resolve_egg_link(path):
    """
    Given a path to an .egg-link, resolve distributions
    present in the referenced path.
    """
    referenced_paths = non_empty_lines(path)
    resolved_paths = (
        os.path.join(os.path.dirname(path), ref) for ref in referenced_paths
    )
    dist_groups = map(find_distributions, resolved_paths)
    return next(dist_groups, ())


if hasattr(pkgutil, 'ImpImporter'):
    register_finder(pkgutil.ImpImporter, find_on_path)

register_finder(importlib_machinery.FileFinder, find_on_path)

_declare_state('dict', _namespace_handlers={})
_declare_state('dict', _namespace_packages={})


def register_namespace_handler(importer_type, namespace_handler):
    """Register `namespace_handler` to declare namespace packages

    `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
    handler), and `namespace_handler` is a callable like this::

        def namespace_handler(importer, path_entry, moduleName, module):
            # return a path_entry to use for child packages

    Namespace handlers are only called if the importer object has already
    agreed that it can handle the relevant path item, and they should only
    return a subpath if the module __path__ does not already contain an
    equivalent subpath.  For an example namespace handler, see
    ``pkg_resources.file_ns_handler``.
    """
    _namespace_handlers[importer_type] = namespace_handler


def _handle_ns(packageName, path_item):
    """Ensure that named package includes a subpath of path_item (if needed)"""

    importer = get_importer(path_item)
    if importer is None:
        return None

    # use find_spec (PEP 451) and fall-back to find_module (PEP 302)
    try:
        spec = importer.find_spec(packageName)
    except AttributeError:
        # capture warnings due to #1111
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            loader = importer.find_module(packageName)
    else:
        loader = spec.loader if spec else None

    if loader is None:
        return None
    module = sys.modules.get(packageName)
    if module is None:
        module = sys.modules[packageName] = types.ModuleType(packageName)
        module.__path__ = []
        _set_parent_ns(packageName)
    elif not hasattr(module, '__path__'):
        raise TypeError("Not a package:", packageName)
    handler = _find_adapter(_namespace_handlers, importer)
    subpath = handler(importer, path_item, packageName, module)
    if subpath is not None:
        path = module.__path__
        path.append(subpath)
        importlib.import_module(packageName)
        _rebuild_mod_path(path, packageName, module)
    return subpath


def _rebuild_mod_path(orig_path, package_name, module):
    """
    Rebuild module.__path__ ensuring that all entries are ordered
    corresponding to their sys.path order
    """
    sys_path = [_normalize_cached(p) for p in sys.path]

    def safe_sys_path_index(entry):
        """
        Workaround for #520 and #513.
        """
        try:
            return sys_path.index(entry)
        except ValueError:
            return float('inf')

    def position_in_sys_path(path):
        """
        Return the ordinal of the path based on its position in sys.path
        """
        path_parts = path.split(os.sep)
        module_parts = package_name.count('.') + 1
        parts = path_parts[:-module_parts]
        return safe_sys_path_index(_normalize_cached(os.sep.join(parts)))

    new_path = sorted(orig_path, key=position_in_sys_path)
    new_path = [_normalize_cached(p) for p in new_path]

    if isinstance(module.__path__, list):
        module.__path__[:] = new_path
    else:
        module.__path__ = new_path


def declare_namespace(packageName):
    """Declare that package 'packageName' is a namespace package"""

    _imp.acquire_lock()
    try:
        if packageName in _namespace_packages:
            return

        path = sys.path
        parent, _, _ = packageName.rpartition('.')

        if parent:
            declare_namespace(parent)
            if parent not in _namespace_packages:
                __import__(parent)
            try:
                path = sys.modules[parent].__path__
            except AttributeError as e:
                raise TypeError("Not a package:", parent) from e

        # Track what packages are namespaces, so when new path items are added,
        # they can be updated
        _namespace_packages.setdefault(parent or None, []).append(packageName)
        _namespace_packages.setdefault(packageName, [])

        for path_item in path:
            # Ensure all the parent's path items are reflected in the child,
            # if they apply
            _handle_ns(packageName, path_item)

    finally:
        _imp.release_lock()


def fixup_namespace_packages(path_item, parent=None):
    """Ensure that previously-declared namespace packages include path_item"""
    _imp.acquire_lock()
    try:
        for package in _namespace_packages.get(parent, ()):
            subpath = _handle_ns(package, path_item)
            if subpath:
                fixup_namespace_packages(subpath, package)
    finally:
        _imp.release_lock()


def file_ns_handler(importer, path_item, packageName, module):
    """Compute an ns-package subpath for a filesystem or zipfile importer"""

    subpath = os.path.join(path_item, packageName.split('.')[-1])
    normalized = _normalize_cached(subpath)
    for item in module.__path__:
        if _normalize_cached(item) == normalized:
            break
    else:
        # Only return the path if it's not already there
        return subpath


if hasattr(pkgutil, 'ImpImporter'):
    register_namespace_handler(pkgutil.ImpImporter, file_ns_handler)

register_namespace_handler(zipimport.zipimporter, file_ns_handler)
register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler)


def null_ns_handler(importer, path_item, packageName, module):
    return None


register_namespace_handler(object, null_ns_handler)


def normalize_path(filename):
    """Normalize a file/dir name for comparison purposes"""
    return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename))))


def _cygwin_patch(filename):  # pragma: nocover
    """
    Contrary to POSIX 2008, on Cygwin, getcwd (3) contains
    symlink components. Using
    os.path.abspath() works around this limitation. A fix in os.getcwd()
    would probably better, in Cygwin even more so, except
    that this seems to be by design...
    """
    return os.path.abspath(filename) if sys.platform == 'cygwin' else filename


def _normalize_cached(filename, _cache={}):
    try:
        return _cache[filename]
    except KeyError:
        _cache[filename] = result = normalize_path(filename)
        return result


def _is_egg_path(path):
    """
    Determine if given path appears to be an egg.
    """
    return _is_zip_egg(path) or _is_unpacked_egg(path)


def _is_zip_egg(path):
    return (
        path.lower().endswith('.egg')
        and os.path.isfile(path)
        and zipfile.is_zipfile(path)
    )


def _is_unpacked_egg(path):
    """
    Determine if given path appears to be an unpacked egg.
    """
    return path.lower().endswith('.egg') and os.path.isfile(
        os.path.join(path, 'EGG-INFO', 'PKG-INFO')
    )


def _set_parent_ns(packageName):
    parts = packageName.split('.')
    name = parts.pop()
    if parts:
        parent = '.'.join(parts)
        setattr(sys.modules[parent], name, sys.modules[packageName])


MODULE = re.compile(r"\w+(\.\w+)*$").match
EGG_NAME = re.compile(
    r"""
    (?P<name>[^-]+) (
        -(?P<ver>[^-]+) (
            -py(?P<pyver>[^-]+) (
                -(?P<plat>.+)
            )?
        )?
    )?
    """,
    re.VERBOSE | re.IGNORECASE,
).match


class EntryPoint:
    """Object representing an advertised importable object"""

    def __init__(self, name, module_name, attrs=(), extras=(), dist=None):
        if not MODULE(module_name):
            raise ValueError("Invalid module name", module_name)
        self.name = name
        self.module_name = module_name
        self.attrs = tuple(attrs)
        self.extras = tuple(extras)
        self.dist = dist

    def __str__(self):
        s = "%s = %s" % (self.name, self.module_name)
        if self.attrs:
            s += ':' + '.'.join(self.attrs)
        if self.extras:
            s += ' [%s]' % ','.join(self.extras)
        return s

    def __repr__(self):
        return "EntryPoint.parse(%r)" % str(self)

    def load(self, require=True, *args, **kwargs):
        """
        Require packages for this EntryPoint, then resolve it.
        """
        if not require or args or kwargs:
            warnings.warn(
                "Parameters to load are deprecated.  Call .resolve and "
                ".require separately.",
                PkgResourcesDeprecationWarning,
                stacklevel=2,
            )
        if require:
            self.require(*args, **kwargs)
        return self.resolve()

    def resolve(self):
        """
        Resolve the entry point from its module and attrs.
        """
        module = __import__(self.module_name, fromlist=['__name__'], level=0)
        try:
            return functools.reduce(getattr, self.attrs, module)
        except AttributeError as exc:
            raise ImportError(str(exc)) from exc

    def require(self, env=None, installer=None):
        if self.extras and not self.dist:
            raise UnknownExtra("Can't require() without a distribution", self)

        # Get the requirements for this entry point with all its extras and
        # then resolve them. We have to pass `extras` along when resolving so
        # that the working set knows what extras we want. Otherwise, for
        # dist-info distributions, the working set will assume that the
        # requirements for that extra are purely optional and skip over them.
        reqs = self.dist.requires(self.extras)
        items = working_set.resolve(reqs, env, installer, extras=self.extras)
        list(map(working_set.add, items))

    pattern = re.compile(
        r'\s*'
        r'(?P<name>.+?)\s*'
        r'=\s*'
        r'(?P<module>[\w.]+)\s*'
        r'(:\s*(?P<attr>[\w.]+))?\s*'
        r'(?P<extras>\[.*\])?\s*$'
    )

    @classmethod
    def parse(cls, src, dist=None):
        """Parse a single entry point from string `src`

        Entry point syntax follows the form::

            name = some.module:some.attr [extra1, extra2]

        The entry name and module name are required, but the ``:attrs`` and
        ``[extras]`` parts are optional
        """
        m = cls.pattern.match(src)
        if not m:
            msg = "EntryPoint must be in 'name=module:attrs [extras]' format"
            raise ValueError(msg, src)
        res = m.groupdict()
        extras = cls._parse_extras(res['extras'])
        attrs = res['attr'].split('.') if res['attr'] else ()
        return cls(res['name'], res['module'], attrs, extras, dist)

    @classmethod
    def _parse_extras(cls, extras_spec):
        if not extras_spec:
            return ()
        req = Requirement.parse('x' + extras_spec)
        if req.specs:
            raise ValueError()
        return req.extras

    @classmethod
    def parse_group(cls, group, lines, dist=None):
        """Parse an entry point group"""
        if not MODULE(group):
            raise ValueError("Invalid group name", group)
        this = {}
        for line in yield_lines(lines):
            ep = cls.parse(line, dist)
            if ep.name in this:
                raise ValueError("Duplicate entry point", group, ep.name)
            this[ep.name] = ep
        return this

    @classmethod
    def parse_map(cls, data, dist=None):
        """Parse a map of entry point groups"""
        if isinstance(data, dict):
            data = data.items()
        else:
            data = split_sections(data)
        maps = {}
        for group, lines in data:
            if group is None:
                if not lines:
                    continue
                raise ValueError("Entry points must be listed in groups")
            group = group.strip()
            if group in maps:
                raise ValueError("Duplicate group name", group)
            maps[group] = cls.parse_group(group, lines, dist)
        return maps


def _version_from_file(lines):
    """
    Given an iterable of lines from a Metadata file, return
    the value of the Version field, if present, or None otherwise.
    """

    def is_version_line(line):
        return line.lower().startswith('version:')

    version_lines = filter(is_version_line, lines)
    line = next(iter(version_lines), '')
    _, _, value = line.partition(':')
    return safe_version(value.strip()) or None


class Distribution:
    """Wrap an actual or potential sys.path entry w/metadata"""

    PKG_INFO = 'PKG-INFO'

    def __init__(
        self,
        location=None,
        metadata=None,
        project_name=None,
        version=None,
        py_version=PY_MAJOR,
        platform=None,
        precedence=EGG_DIST,
    ):
        self.project_name = safe_name(project_name or 'Unknown')
        if version is not None:
            self._version = safe_version(version)
        self.py_version = py_version
        self.platform = platform
        self.location = location
        self.precedence = precedence
        self._provider = metadata or empty_provider

    @classmethod
    def from_location(cls, location, basename, metadata=None, **kw):
        project_name, version, py_version, platform = [None] * 4
        basename, ext = os.path.splitext(basename)
        if ext.lower() in _distributionImpl:
            cls = _distributionImpl[ext.lower()]

            match = EGG_NAME(basename)
            if match:
                project_name, version, py_version, platform = match.group(
                    'name', 'ver', 'pyver', 'plat'
                )
        return cls(
            location,
            metadata,
            project_name=project_name,
            version=version,
            py_version=py_version,
            platform=platform,
            **kw,
        )._reload_version()

    def _reload_version(self):
        return self

    @property
    def hashcmp(self):
        return (
            self.parsed_version,
            self.precedence,
            self.key,
            self.location,
            self.py_version or '',
            self.platform or '',
        )

    def __hash__(self):
        return hash(self.hashcmp)

    def __lt__(self, other):
        return self.hashcmp < other.hashcmp

    def __le__(self, other):
        return self.hashcmp <= other.hashcmp

    def __gt__(self, other):
        return self.hashcmp > other.hashcmp

    def __ge__(self, other):
        return self.hashcmp >= other.hashcmp

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            # It's not a Distribution, so they are not equal
            return False
        return self.hashcmp == other.hashcmp

    def __ne__(self, other):
        return not self == other

    # These properties have to be lazy so that we don't have to load any
    # metadata until/unless it's actually needed.  (i.e., some distributions
    # may not know their name or version without loading PKG-INFO)

    @property
    def key(self):
        try:
            return self._key
        except AttributeError:
            self._key = key = self.project_name.lower()
            return key

    @property
    def parsed_version(self):
        if not hasattr(self, "_parsed_version"):
            try:
                self._parsed_version = parse_version(self.version)
            except packaging.version.InvalidVersion as ex:
                info = f"(package: {self.project_name})"
                if hasattr(ex, "add_note"):
                    ex.add_note(info)  # PEP 678
                    raise
                raise packaging.version.InvalidVersion(f"{str(ex)} {info}") from None

        return self._parsed_version

    @property
    def version(self):
        try:
            return self._version
        except AttributeError as e:
            version = self._get_version()
            if version is None:
                path = self._get_metadata_path_for_display(self.PKG_INFO)
                msg = ("Missing 'Version:' header and/or {} file at path: {}").format(
                    self.PKG_INFO, path
                )
                raise ValueError(msg, self) from e

            return version

    @property
    def _dep_map(self):
        """
        A map of extra to its list of (direct) requirements
        for this distribution, including the null extra.
        """
        try:
            return self.__dep_map
        except AttributeError:
            self.__dep_map = self._filter_extras(self._build_dep_map())
        return self.__dep_map

    @staticmethod
    def _filter_extras(dm):
        """
        Given a mapping of extras to dependencies, strip off
        environment markers and filter out any dependencies
        not matching the markers.
        """
        for extra in list(filter(None, dm)):
            new_extra = extra
            reqs = dm.pop(extra)
            new_extra, _, marker = extra.partition(':')
            fails_marker = marker and (
                invalid_marker(marker) or not evaluate_marker(marker)
            )
            if fails_marker:
                reqs = []
            new_extra = safe_extra(new_extra) or None

            dm.setdefault(new_extra, []).extend(reqs)
        return dm

    def _build_dep_map(self):
        dm = {}
        for name in 'requires.txt', 'depends.txt':
            for extra, reqs in split_sections(self._get_metadata(name)):
                dm.setdefault(extra, []).extend(parse_requirements(reqs))
        return dm

    def requires(self, extras=()):
        """List of Requirements needed for this distro if `extras` are used"""
        dm = self._dep_map
        deps = []
        deps.extend(dm.get(None, ()))
        for ext in extras:
            try:
                deps.extend(dm[safe_extra(ext)])
            except KeyError as e:
                raise UnknownExtra(
                    "%s has no such extra feature %r" % (self, ext)
                ) from e
        return deps

    def _get_metadata_path_for_display(self, name):
        """
        Return the path to the given metadata file, if available.
        """
        try:
            # We need to access _get_metadata_path() on the provider object
            # directly rather than through this class's __getattr__()
            # since _get_metadata_path() is marked private.
            path = self._provider._get_metadata_path(name)

        # Handle exceptions e.g. in case the distribution's metadata
        # provider doesn't support _get_metadata_path().
        except Exception:
            return '[could not detect]'

        return path

    def _get_metadata(self, name):
        if self.has_metadata(name):
            for line in self.get_metadata_lines(name):
                yield line

    def _get_version(self):
        lines = self._get_metadata(self.PKG_INFO)
        version = _version_from_file(lines)

        return version

    def activate(self, path=None, replace=False):
        """Ensure distribution is importable on `path` (default=sys.path)"""
        if path is None:
            path = sys.path
        self.insert_on(path, replace=replace)
        if path is sys.path:
            fixup_namespace_packages(self.location)
            for pkg in self._get_metadata('namespace_packages.txt'):
                if pkg in sys.modules:
                    declare_namespace(pkg)

    def egg_name(self):
        """Return what this distribution's standard .egg filename should be"""
        filename = "%s-%s-py%s" % (
            to_filename(self.project_name),
            to_filename(self.version),
            self.py_version or PY_MAJOR,
        )

        if self.platform:
            filename += '-' + self.platform
        return filename

    def __repr__(self):
        if self.location:
            return "%s (%s)" % (self, self.location)
        else:
            return str(self)

    def __str__(self):
        try:
            version = getattr(self, 'version', None)
        except ValueError:
            version = None
        version = version or "[unknown version]"
        return "%s %s" % (self.project_name, version)

    def __getattr__(self, attr):
        """Delegate all unrecognized public attributes to .metadata provider"""
        if attr.startswith('_'):
            raise AttributeError(attr)
        return getattr(self._provider, attr)

    def __dir__(self):
        return list(
            set(super(Distribution, self).__dir__())
            | set(attr for attr in self._provider.__dir__() if not attr.startswith('_'))
        )

    @classmethod
    def from_filename(cls, filename, metadata=None, **kw):
        return cls.from_location(
            _normalize_cached(filename), os.path.basename(filename), metadata, **kw
        )

    def as_requirement(self):
        """Return a ``Requirement`` that matches this distribution exactly"""
        if isinstance(self.parsed_version, packaging.version.Version):
            spec = "%s==%s" % (self.project_name, self.parsed_version)
        else:
            spec = "%s===%s" % (self.project_name, self.parsed_version)

        return Requirement.parse(spec)

    def load_entry_point(self, group, name):
        """Return the `name` entry point of `group` or raise ImportError"""
        ep = self.get_entry_info(group, name)
        if ep is None:
            raise ImportError("Entry point %r not found" % ((group, name),))
        return ep.load()

    def get_entry_map(self, group=None):
        """Return the entry point map for `group`, or the full entry map"""
        try:
            ep_map = self._ep_map
        except AttributeError:
            ep_map = self._ep_map = EntryPoint.parse_map(
                self._get_metadata('entry_points.txt'), self
            )
        if group is not None:
            return ep_map.get(group, {})
        return ep_map

    def get_entry_info(self, group, name):
        """Return the EntryPoint object for `group`+`name`, or ``None``"""
        return self.get_entry_map(group).get(name)

    # FIXME: 'Distribution.insert_on' is too complex (13)
    def insert_on(self, path, loc=None, replace=False):  # noqa: C901
        """Ensure self.location is on path

        If replace=False (default):
            - If location is already in path anywhere, do nothing.
            - Else:
              - If it's an egg and its parent directory is on path,
                insert just ahead of the parent.
              - Else: add to the end of path.
        If replace=True:
            - If location is already on path anywhere (not eggs)
              or higher priority than its parent (eggs)
              do nothing.
            - Else:
              - If it's an egg and its parent directory is on path,
                insert just ahead of the parent,
                removing any lower-priority entries.
              - Else: add it to the front of path.
        """

        loc = loc or self.location
        if not loc:
            return

        nloc = _normalize_cached(loc)
        bdir = os.path.dirname(nloc)
        npath = [(p and _normalize_cached(p) or p) for p in path]

        for p, item in enumerate(npath):
            if item == nloc:
                if replace:
                    break
                else:
                    # don't modify path (even removing duplicates) if
                    # found and not replace
                    return
            elif item == bdir and self.precedence == EGG_DIST:
                # if it's an .egg, give it precedence over its directory
                # UNLESS it's already been added to sys.path and replace=False
                if (not replace) and nloc in npath[p:]:
                    return
                if path is sys.path:
                    self.check_version_conflict()
                path.insert(p, loc)
                npath.insert(p, nloc)
                break
        else:
            if path is sys.path:
                self.check_version_conflict()
            if replace:
                path.insert(0, loc)
            else:
                path.append(loc)
            return

        # p is the spot where we found or inserted loc; now remove duplicates
        while True:
            try:
                np = npath.index(nloc, p + 1)
            except ValueError:
                break
            else:
                del npath[np], path[np]
                # ha!
                p = np

        return

    def check_version_conflict(self):
        if self.key == 'setuptools':
            # ignore the inevitable setuptools self-conflicts  :(
            return

        nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt'))
        loc = normalize_path(self.location)
        for modname in self._get_metadata('top_level.txt'):
            if (
                modname not in sys.modules
                or modname in nsp
                or modname in _namespace_packages
            ):
                continue
            if modname in ('pkg_resources', 'setuptools', 'site'):
                continue
            fn = getattr(sys.modules[modname], '__file__', None)
            if fn and (
                normalize_path(fn).startswith(loc) or fn.startswith(self.location)
            ):
                continue
            issue_warning(
                "Module %s was already imported from %s, but %s is being added"
                " to sys.path" % (modname, fn, self.location),
            )

    def has_version(self):
        try:
            self.version
        except ValueError:
            issue_warning("Unbuilt egg for " + repr(self))
            return False
        return True

    def clone(self, **kw):
        """Copy this distribution, substituting in any changed keyword args"""
        names = 'project_name version py_version platform location precedence'
        for attr in names.split():
            kw.setdefault(attr, getattr(self, attr, None))
        kw.setdefault('metadata', self._provider)
        return self.__class__(**kw)

    @property
    def extras(self):
        return [dep for dep in self._dep_map if dep]


class EggInfoDistribution(Distribution):
    def _reload_version(self):
        """
        Packages installed by distutils (e.g. numpy or scipy),
        which uses an old safe_version, and so
        their version numbers can get mangled when
        converted to filenames (e.g., 1.11.0.dev0+2329eae to
        1.11.0.dev0_2329eae). These distributions will not be
        parsed properly
        downstream by Distribution and safe_version, so
        take an extra step and try to get the version number from
        the metadata file itself instead of the filename.
        """
        md_version = self._get_version()
        if md_version:
            self._version = md_version
        return self


class DistInfoDistribution(Distribution):
    """
    Wrap an actual or potential sys.path entry
    w/metadata, .dist-info style.
    """

    PKG_INFO = 'METADATA'
    EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")

    @property
    def _parsed_pkg_info(self):
        """Parse and cache metadata"""
        try:
            return self._pkg_info
        except AttributeError:
            metadata = self.get_metadata(self.PKG_INFO)
            self._pkg_info = email.parser.Parser().parsestr(metadata)
            return self._pkg_info

    @property
    def _dep_map(self):
        try:
            return self.__dep_map
        except AttributeError:
            self.__dep_map = self._compute_dependencies()
            return self.__dep_map

    def _compute_dependencies(self):
        """Recompute this distribution's dependencies."""
        dm = self.__dep_map = {None: []}

        reqs = []
        # Including any condition expressions
        for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
            reqs.extend(parse_requirements(req))

        def reqs_for_extra(extra):
            for req in reqs:
                if not req.marker or req.marker.evaluate({'extra': extra}):
                    yield req

        common = types.MappingProxyType(dict.fromkeys(reqs_for_extra(None)))
        dm[None].extend(common)

        for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
            s_extra = safe_extra(extra.strip())
            dm[s_extra] = [r for r in reqs_for_extra(extra) if r not in common]

        return dm


_distributionImpl = {
    '.egg': Distribution,
    '.egg-info': EggInfoDistribution,
    '.dist-info': DistInfoDistribution,
}


def issue_warning(*args, **kw):
    level = 1
    g = globals()
    try:
        # find the first stack frame that is *not* code in
        # the pkg_resources module, to use for the warning
        while sys._getframe(level).f_globals is g:
            level += 1
    except ValueError:
        pass
    warnings.warn(stacklevel=level + 1, *args, **kw)


def parse_requirements(strs):
    """
    Yield ``Requirement`` objects for each specification in `strs`.

    `strs` must be a string, or a (possibly-nested) iterable thereof.
    """
    return map(Requirement, join_continuation(map(drop_comment, yield_lines(strs))))


class RequirementParseError(packaging.requirements.InvalidRequirement):
    "Compatibility wrapper for InvalidRequirement"


class Requirement(packaging.requirements.Requirement):
    def __init__(self, requirement_string):
        """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
        super(Requirement, self).__init__(requirement_string)
        self.unsafe_name = self.name
        project_name = safe_name(self.name)
        self.project_name, self.key = project_name, project_name.lower()
        self.specs = [(spec.operator, spec.version) for spec in self.specifier]
        self.extras = tuple(map(safe_extra, self.extras))
        self.hashCmp = (
            self.key,
            self.url,
            self.specifier,
            frozenset(self.extras),
            str(self.marker) if self.marker else None,
        )
        self.__hash = hash(self.hashCmp)

    def __eq__(self, other):
        return isinstance(other, Requirement) and self.hashCmp == other.hashCmp

    def __ne__(self, other):
        return not self == other

    def __contains__(self, item):
        if isinstance(item, Distribution):
            if item.key != self.key:
                return False

            item = item.version

        # Allow prereleases always in order to match the previous behavior of
        # this method. In the future this should be smarter and follow PEP 440
        # more accurately.
        return self.specifier.contains(item, prereleases=True)

    def __hash__(self):
        return self.__hash

    def __repr__(self):
        return "Requirement.parse(%r)" % str(self)

    @staticmethod
    def parse(s):
        (req,) = parse_requirements(s)
        return req


def _always_object(classes):
    """
    Ensure object appears in the mro even
    for old-style classes.
    """
    if object not in classes:
        return classes + (object,)
    return classes


def _find_adapter(registry, ob):
    """Return an adapter factory for `ob` from `registry`"""
    types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob))))
    for t in types:
        if t in registry:
            return registry[t]


def ensure_directory(path):
    """Ensure that the parent directory of `path` exists"""
    dirname = os.path.dirname(path)
    os.makedirs(dirname, exist_ok=True)


def _bypass_ensure_directory(path):
    """Sandbox-bypassing version of ensure_directory()"""
    if not WRITE_SUPPORT:
        raise IOError('"os.mkdir" not supported on this platform.')
    dirname, filename = split(path)
    if dirname and filename and not isdir(dirname):
        _bypass_ensure_directory(dirname)
        try:
            mkdir(dirname, 0o755)
        except FileExistsError:
            pass


def split_sections(s):
    """Split a string or iterable thereof into (section, content) pairs

    Each ``section`` is a stripped version of the section header ("[section]")
    and each ``content`` is a list of stripped lines excluding blank lines and
    comment-only lines.  If there are any such lines before the first section
    header, they're returned in a first ``section`` of ``None``.
    """
    section = None
    content = []
    for line in yield_lines(s):
        if line.startswith("["):
            if line.endswith("]"):
                if section or content:
                    yield section, content
                section = line[1:-1].strip()
                content = []
            else:
                raise ValueError("Invalid section heading", line)
        else:
            content.append(line)

    # wrap up last segment
    yield section, content


def _mkstemp(*args, **kw):
    old_open = os.open
    try:
        # temporarily bypass sandboxing
        os.open = os_open
        return tempfile.mkstemp(*args, **kw)
    finally:
        # and then put it back
        os.open = old_open


# Silence the PEP440Warning by default, so that end users don't get hit by it
# randomly just because they use pkg_resources. We want to append the rule
# because we want earlier uses of filterwarnings to take precedence over this
# one.
warnings.filterwarnings("ignore", category=PEP440Warning, append=True)


# from jaraco.functools 1.3
def _call_aside(f, *args, **kwargs):
    f(*args, **kwargs)
    return f


@_call_aside
def _initialize(g=globals()):
    "Set up global resource manager (deliberately not state-saved)"
    manager = ResourceManager()
    g['_manager'] = manager
    g.update(
        (name, getattr(manager, name))
        for name in dir(manager)
        if not name.startswith('_')
    )


class PkgResourcesDeprecationWarning(Warning):
    """
    Base class for warning about deprecations in ``pkg_resources``

    This class is not derived from ``DeprecationWarning``, and as such is
    visible by default.
    """


@_call_aside
def _initialize_master_working_set():
    """
    Prepare the master working set and make the ``require()``
    API available.

    This function has explicit effects on the global state
    of pkg_resources. It is intended to be invoked once at
    the initialization of this module.

    Invocation by other packages is unsupported and done
    at their own risk.
    """
    working_set = WorkingSet._build_master()
    _declare_state('object', working_set=working_set)

    require = working_set.require
    iter_entry_points = working_set.iter_entry_points
    add_activation_listener = working_set.subscribe
    run_script = working_set.run_script
    # backward compatibility
    run_main = run_script
    # Activate all distributions already on sys.path with replace=False and
    # ensure that all distributions added to the working set in the future
    # (e.g. by calling ``require()``) will get activated as well,
    # with higher priority (replace=True).
    tuple(dist.activate(replace=False) for dist in working_set)
    add_activation_listener(
        lambda dist: dist.activate(replace=True),
        existing=False,
    )
    working_set.entries = []
    # match order
    list(map(working_set.add_entry, sys.path))
    globals().update(locals())
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          import warnings

from collections import Counter, defaultdict, deque, abc
from collections.abc import Sequence
from functools import partial, reduce, wraps
from heapq import heapify, heapreplace, heappop
from itertools import (
    chain,
    compress,
    count,
    cycle,
    dropwhile,
    groupby,
    islice,
    repeat,
    starmap,
    takewhile,
    tee,
    zip_longest,
)
from math import exp, factorial, floor, log
from queue import Empty, Queue
from random import random, randrange, uniform
from operator import itemgetter, mul, sub, gt, lt, ge, le
from sys import hexversion, maxsize
from time import monotonic

from .recipes import (
    _marker,
    _zip_equal,
    UnequalIterablesError,
    consume,
    flatten,
    pairwise,
    powerset,
    take,
    unique_everseen,
    all_equal,
)

__all__ = [
    'AbortThread',
    'SequenceView',
    'UnequalIterablesError',
    'adjacent',
    'all_unique',
    'always_iterable',
    'always_reversible',
    'bucket',
    'callback_iter',
    'chunked',
    'chunked_even',
    'circular_shifts',
    'collapse',
    'combination_index',
    'consecutive_groups',
    'constrained_batches',
    'consumer',
    'count_cycle',
    'countable',
    'difference',
    'distinct_combinations',
    'distinct_permutations',
    'distribute',
    'divide',
    'duplicates_everseen',
    'duplicates_justseen',
    'exactly_n',
    'filter_except',
    'first',
    'groupby_transform',
    'ichunked',
    'iequals',
    'ilen',
    'interleave',
    'interleave_evenly',
    'interleave_longest',
    'intersperse',
    'is_sorted',
    'islice_extended',
    'iterate',
    'last',
    'locate',
    'longest_common_prefix',
    'lstrip',
    'make_decorator',
    'map_except',
    'map_if',
    'map_reduce',
    'mark_ends',
    'minmax',
    'nth_or_last',
    'nth_permutation',
    'nth_product',
    'numeric_range',
    'one',
    'only',
    'padded',
    'partitions',
    'peekable',
    'permutation_index',
    'product_index',
    'raise_',
    'repeat_each',
    'repeat_last',
    'replace',
    'rlocate',
    'rstrip',
    'run_length',
    'sample',
    'seekable',
    'set_partitions',
    'side_effect',
    'sliced',
    'sort_together',
    'split_after',
    'split_at',
    'split_before',
    'split_into',
    'split_when',
    'spy',
    'stagger',
    'strip',
    'strictly_n',
    'substrings',
    'substrings_indexes',
    'time_limited',
    'unique_in_window',
    'unique_to_each',
    'unzip',
    'value_chain',
    'windowed',
    'windowed_complete',
    'with_iter',
    'zip_broadcast',
    'zip_equal',
    'zip_offset',
]


def chunked(iterable, n, strict=False):
    """Break *iterable* into lists of length *n*:

        >>> list(chunked([1, 2, 3, 4, 5, 6], 3))
        [[1, 2, 3], [4, 5, 6]]

    By the default, the last yielded list will have fewer than *n* elements
    if the length of *iterable* is not divisible by *n*:

        >>> list(chunked([1, 2, 3, 4, 5, 6, 7, 8], 3))
        [[1, 2, 3], [4, 5, 6], [7, 8]]

    To use a fill-in value instead, see the :func:`grouper` recipe.

    If the length of *iterable* is not divisible by *n* and *strict* is
    ``True``, then ``ValueError`` will be raised before the last
    list is yielded.

    """
    iterator = iter(partial(take, n, iter(iterable)), [])
    if strict:
        if n is None:
            raise ValueError('n must not be None when using strict mode.')

        def ret():
            for chunk in iterator:
                if len(chunk) != n:
                    raise ValueError('iterable is not divisible by n.')
                yield chunk

        return iter(ret())
    else:
        return iterator


def first(iterable, default=_marker):
    """Return the first item of *iterable*, or *default* if *iterable* is
    empty.

        >>> first([0, 1, 2, 3])
        0
        >>> first([], 'some default')
        'some default'

    If *default* is not provided and there are no items in the iterable,
    raise ``ValueError``.

    :func:`first` is useful when you have a generator of expensive-to-retrieve
    values and want any arbitrary one. It is marginally shorter than
    ``next(iter(iterable), default)``.

    """
    try:
        return next(iter(iterable))
    except StopIteration as e:
        if default is _marker:
            raise ValueError(
                'first() was called on an empty iterable, and no '
                'default value was provided.'
            ) from e
        return default


def last(iterable, default=_marker):
    """Return the last item of *iterable*, or *default* if *iterable* is
    empty.

        >>> last([0, 1, 2, 3])
        3
        >>> last([], 'some default')
        'some default'

    If *default* is not provided and there are no items in the iterable,
    raise ``ValueError``.
    """
    try:
        if isinstance(iterable, Sequence):
            return iterable[-1]
        # Work around https://bugs.python.org/issue38525
        elif hasattr(iterable, '__reversed__') and (hexversion != 0x030800F0):
            return next(reversed(iterable))
        else:
            return deque(iterable, maxlen=1)[-1]
    except (IndexError, TypeError, StopIteration):
        if default is _marker:
            raise ValueError(
                'last() was called on an empty iterable, and no default was '
                'provided.'
            )
        return default


def nth_or_last(iterable, n, default=_marker):
    """Return the nth or the last item of *iterable*,
    or *default* if *iterable* is empty.

        >>> nth_or_last([0, 1, 2, 3], 2)
        2
        >>> nth_or_last([0, 1], 2)
        1
        >>> nth_or_last([], 0, 'some default')
        'some default'

    If *default* is not provided and there are no items in the iterable,
    raise ``ValueError``.
    """
    return last(islice(iterable, n + 1), default=default)


class peekable:
    """Wrap an iterator to allow lookahead and prepending elements.

    Call :meth:`peek` on the result to get the value that will be returned
    by :func:`next`. This won't advance the iterator:

        >>> p = peekable(['a', 'b'])
        >>> p.peek()
        'a'
        >>> next(p)
        'a'

    Pass :meth:`peek` a default value to return that instead of raising
    ``StopIteration`` when the iterator is exhausted.

        >>> p = peekable([])
        >>> p.peek('hi')
        'hi'

    peekables also offer a :meth:`prepend` method, which "inserts" items
    at the head of the iterable:

        >>> p = peekable([1, 2, 3])
        >>> p.prepend(10, 11, 12)
        >>> next(p)
        10
        >>> p.peek()
        11
        >>> list(p)
        [11, 12, 1, 2, 3]

    peekables can be indexed. Index 0 is the item that will be returned by
    :func:`next`, index 1 is the item after that, and so on:
    The values up to the given index will be cached.

        >>> p = peekable(['a', 'b', 'c', 'd'])
        >>> p[0]
        'a'
        >>> p[1]
        'b'
        >>> next(p)
        'a'

    Negative indexes are supported, but be aware that they will cache the
    remaining items in the source iterator, which may require significant
    storage.

    To check whether a peekable is exhausted, check its truth value:

        >>> p = peekable(['a', 'b'])
        >>> if p:  # peekable has items
        ...     list(p)
        ['a', 'b']
        >>> if not p:  # peekable is exhausted
        ...     list(p)
        []

    """

    def __init__(self, iterable):
        self._it = iter(iterable)
        self._cache = deque()

    def __iter__(self):
        return self

    def __bool__(self):
        try:
            self.peek()
        except StopIteration:
            return False
        return True

    def peek(self, default=_marker):
        """Return the item that will be next returned from ``next()``.

        Return ``default`` if there are no items left. If ``default`` is not
        provided, raise ``StopIteration``.

        """
        if not self._cache:
            try:
                self._cache.append(next(self._it))
            except StopIteration:
                if default is _marker:
                    raise
                return default
        return self._cache[0]

    def prepend(self, *items):
        """Stack up items to be the next ones returned from ``next()`` or
        ``self.peek()``. The items will be returned in
        first in, first out order::

            >>> p = peekable([1, 2, 3])
            >>> p.prepend(10, 11, 12)
            >>> next(p)
            10
            >>> list(p)
            [11, 12, 1, 2, 3]

        It is possible, by prepending items, to "resurrect" a peekable that
        previously raised ``StopIteration``.

            >>> p = peekable([])
            >>> next(p)
            Traceback (most recent call last):
              ...
            StopIteration
            >>> p.prepend(1)
            >>> next(p)
            1
            >>> next(p)
            Traceback (most recent call last):
              ...
            StopIteration

        """
        self._cache.extendleft(reversed(items))

    def __next__(self):
        if self._cache:
            return self._cache.popleft()

        return next(self._it)

    def _get_slice(self, index):
        # Normalize the slice's arguments
        step = 1 if (index.step is None) else index.step
        if step > 0:
            start = 0 if (index.start is None) else index.start
            stop = maxsize if (index.stop is None) else index.stop
        elif step < 0:
            start = -1 if (index.start is None) else index.start
            stop = (-maxsize - 1) if (index.stop is None) else index.stop
        else:
            raise ValueError('slice step cannot be zero')

        # If either the start or stop index is negative, we'll need to cache
        # the rest of the iterable in order to slice from the right side.
        if (start < 0) or (stop < 0):
            self._cache.extend(self._it)
        # Otherwise we'll need to find the rightmost index and cache to that
        # point.
        else:
            n = min(max(start, stop) + 1, maxsize)
            cache_len = len(self._cache)
            if n >= cache_len:
                self._cache.extend(islice(self._it, n - cache_len))

        return list(self._cache)[index]

    def __getitem__(self, index):
        if isinstance(index, slice):
            return self._get_slice(index)

        cache_len = len(self._cache)
        if index < 0:
            self._cache.extend(self._it)
        elif index >= cache_len:
            self._cache.extend(islice(self._it, index + 1 - cache_len))

        return self._cache[index]


def consumer(func):
    """Decorator that automatically advances a PEP-342-style "reverse iterator"
    to its first yield point so you don't have to call ``next()`` on it
    manually.

        >>> @consumer
        ... def tally():
        ...     i = 0
        ...     while True:
        ...         print('Thing number %s is %s.' % (i, (yield)))
        ...         i += 1
        ...
        >>> t = tally()
        >>> t.send('red')
        Thing number 0 is red.
        >>> t.send('fish')
        Thing number 1 is fish.

    Without the decorator, you would have to call ``next(t)`` before
    ``t.send()`` could be used.

    """

    @wraps(func)
    def wrapper(*args, **kwargs):
        gen = func(*args, **kwargs)
        next(gen)
        return gen

    return wrapper


def ilen(iterable):
    """Return the number of items in *iterable*.

        >>> ilen(x for x in range(1000000) if x % 3 == 0)
        333334

    This consumes the iterable, so handle with care.

    """
    # This approach was selected because benchmarks showed it's likely the
    # fastest of the known implementations at the time of writing.
    # See GitHub tracker: #236, #230.
    counter = count()
    deque(zip(iterable, counter), maxlen=0)
    return next(counter)


def iterate(func, start):
    """Return ``start``, ``func(start)``, ``func(func(start))``, ...

    >>> from itertools import islice
    >>> list(islice(iterate(lambda x: 2*x, 1), 10))
    [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

    """
    while True:
        yield start
        start = func(start)


def with_iter(context_manager):
    """Wrap an iterable in a ``with`` statement, so it closes once exhausted.

    For example, this will close the file when the iterator is exhausted::

        upper_lines = (line.upper() for line in with_iter(open('foo')))

    Any context manager which returns an iterable is a candidate for
    ``with_iter``.

    """
    with context_manager as iterable:
        yield from iterable


def one(iterable, too_short=None, too_long=None):
    """Return the first item from *iterable*, which is expected to contain only
    that item. Raise an exception if *iterable* is empty or has more than one
    item.

    :func:`one` is useful for ensuring that an iterable contains only one item.
    For example, it can be used to retrieve the result of a database query
    that is expected to return a single row.

    If *iterable* is empty, ``ValueError`` will be raised. You may specify a
    different exception with the *too_short* keyword:

        >>> it = []
        >>> one(it)  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        ValueError: too many items in iterable (expected 1)'
        >>> too_short = IndexError('too few items')
        >>> one(it, too_short=too_short)  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        IndexError: too few items

    Similarly, if *iterable* contains more than one item, ``ValueError`` will
    be raised. You may specify a different exception with the *too_long*
    keyword:

        >>> it = ['too', 'many']
        >>> one(it)  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        ValueError: Expected exactly one item in iterable, but got 'too',
        'many', and perhaps more.
        >>> too_long = RuntimeError
        >>> one(it, too_long=too_long)  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        RuntimeError

    Note that :func:`one` attempts to advance *iterable* twice to ensure there
    is only one item. See :func:`spy` or :func:`peekable` to check iterable
    contents less destructively.

    """
    it = iter(iterable)

    try:
        first_value = next(it)
    except StopIteration as e:
        raise (
            too_short or ValueError('too few items in iterable (expected 1)')
        ) from e

    try:
        second_value = next(it)
    except StopIteration:
        pass
    else:
        msg = (
            'Expected exactly one item in iterable, but got {!r}, {!r}, '
            'and perhaps more.'.format(first_value, second_value)
        )
        raise too_long or ValueError(msg)

    return first_value


def raise_(exception, *args):
    raise exception(*args)


def strictly_n(iterable, n, too_short=None, too_long=None):
    """Validate that *iterable* has exactly *n* items and return them if
    it does. If it has fewer than *n* items, call function *too_short*
    with those items. If it has more than *n* items, call function
    *too_long* with the first ``n + 1`` items.

        >>> iterable = ['a', 'b', 'c', 'd']
        >>> n = 4
        >>> list(strictly_n(iterable, n))
        ['a', 'b', 'c', 'd']

    By default, *too_short* and *too_long* are functions that raise
    ``ValueError``.

        >>> list(strictly_n('ab', 3))  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        ValueError: too few items in iterable (got 2)

        >>> list(strictly_n('abc', 2))  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        ValueError: too many items in iterable (got at least 3)

    You can instead supply functions that do something else.
    *too_short* will be called with the number of items in *iterable*.
    *too_long* will be called with `n + 1`.

        >>> def too_short(item_count):
        ...     raise RuntimeError
        >>> it = strictly_n('abcd', 6, too_short=too_short)
        >>> list(it)  # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        RuntimeError

        >>> def too_long(item_count):
        ...     print('The boss is going to hear about this')
        >>> it = strictly_n('abcdef', 4, too_long=too_long)
        >>> list(it)
        The boss is going to hear about this
        ['a', 'b', 'c', 'd']

    """
    if too_short is None:
        too_short = lambda item_count: raise_(
            ValueError,
            'Too few items in iterable (got {})'.format(item_count),
        )

    if too_long is None:
        too_long = lambda item_count: raise_(
            ValueError,
            'Too many items in iterable (got at least {})'.format(item_count),
        )

    it = iter(iterable)
    for i in range(n):
        try:
            item = next(it)
        except StopIteration:
            too_short(i)
            return
        else:
            yield item

    try:
        next(it)
    except StopIteration:
        pass
    else:
        too_long(n + 1)


def distinct_permutations(iterable, r=None):
    """Yield successive distinct permutations of the elements in *iterable*.

        >>> sorted(distinct_permutations([1, 0, 1]))
        [(0, 1, 1), (1, 0, 1), (1, 1, 0)]

    Equivalent to ``set(permutations(iterable))``, except duplicates are not
    generated and thrown away. For larger input sequences this is much more
    efficient.

    Duplicate permutations arise when there are duplicated elements in the
    input iterable. The number of items returned is
    `n! / (x_1! * x_2! * ... * x_n!)`, where `n` is the total number of
    items input, and each `x_i` is the count of a distinct item in the input
    sequence.

    If *r* is given, only the *r*-length permutations are yielded.

        >>> sorted(distinct_permutations([1, 0, 1], r=2))
        [(0, 1), (1, 0), (1, 1)]
        >>> sorted(distinct_permutations(range(3), r=2))
        [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]

    """
    # Algorithm: https://w.wiki/Qai
    def _full(A):
        while True:
            # Yield the permutation we have
            yield tuple(A)

            # Find the largest index i such that A[i] < A[i + 1]
            for i in range(size - 2, -1, -1):
                if A[i] < A[i + 1]:
                    break
            #  If no such index exists, this permutation is the last one
            else:
                return

            # Find the largest index j greater than j such that A[i] < A[j]
            for j in range(size - 1, i, -1):
                if A[i] < A[j]:
                    break

            # Swap the value of A[i] with that of A[j], then reverse the
            # sequence from A[i + 1] to form the new permutation
            A[i], A[j] = A[j], A[i]
            A[i + 1 :] = A[: i - size : -1]  # A[i + 1:][::-1]

    # Algorithm: modified from the above
    def _partial(A, r):
        # Split A into the first r items and the last r items
        head, tail = A[:r], A[r:]
        right_head_indexes = range(r - 1, -1, -1)
        left_tail_indexes = range(len(tail))

        while True:
            # Yield the permutation we have
            yield tuple(head)

            # Starting from the right, find the first index of the head with
            # value smaller than the maximum value of the tail - call it i.
            pivot = tail[-1]
            for i in right_head_indexes:
                if head[i] < pivot:
                    break
                pivot = head[i]
            else:
                return

            # Starting from the left, find the first value of the tail
            # with a value greater than head[i] and swap.
            for j in left_tail_indexes:
                if tail[j] > head[i]:
                    head[i], tail[j] = tail[j], head[i]
                    break
            # If we didn't find one, start from the right and find the first
            # index of the head with a value greater than head[i] and swap.
            else:
                for j in right_head_indexes:
                    if head[j] > head[i]:
                        head[i], head[j] = head[j], head[i]
                        break

            # Reverse head[i + 1:] and swap it with tail[:r - (i + 1)]
            tail += head[: i - r : -1]  # head[i + 1:][::-1]
            i += 1
            head[i:], tail[:] = tail[: r - i], tail[r - i :]

    items = sorted(iterable)

    size = len(items)
    if r is None:
        r = size

    if 0 < r <= size:
        return _full(items) if (r == size) else _partial(items, r)

    return iter(() if r else ((),))


def intersperse(e, iterable, n=1):
    """Intersperse filler element *e* among the items in *iterable*, leaving
    *n* items between each filler element.

        >>> list(intersperse('!', [1, 2, 3, 4, 5]))
        [1, '!', 2, '!', 3, '!', 4, '!', 5]

        >>> list(intersperse(None, [1, 2, 3, 4, 5], n=2))
        [1, 2, None, 3, 4, None, 5]

    """
    if n == 0:
        raise ValueError('n must be > 0')
    elif n == 1:
        # interleave(repeat(e), iterable) -> e, x_0, e, x_1, e, x_2...
        # islice(..., 1, None) -> x_0, e, x_1, e, x_2...
        return islice(interleave(repeat(e), iterable), 1, None)
    else:
        # interleave(filler, chunks) -> [e], [x_0, x_1], [e], [x_2, x_3]...
        # islice(..., 1, None) -> [x_0, x_1], [e], [x_2, x_3]...
        # flatten(...) -> x_0, x_1, e, x_2, x_3...
        filler = repeat([e])
        chunks = chunked(iterable, n)
        return flatten(islice(interleave(filler, chunks), 1, None))


def unique_to_each(*iterables):
    """Return the elements from each of the input iterables that aren't in the
    other input iterables.

    For example, suppose you have a set of packages, each with a set of
    dependencies::

        {'pkg_1': {'A', 'B'}, 'pkg_2': {'B', 'C'}, 'pkg_3': {'B', 'D'}}

    If you remove one package, which dependencies can also be removed?

    If ``pkg_1`` is removed, then ``A`` is no longer necessary - it is not
    associated with ``pkg_2`` or ``pkg_3``. Similarly, ``C`` is only needed for
    ``pkg_2``, and ``D`` is only needed for ``pkg_3``::

        >>> unique_to_each({'A', 'B'}, {'B', 'C'}, {'B', 'D'})
        [['A'], ['C'], ['D']]

    If there are duplicates in one input iterable that aren't in the others
    they will be duplicated in the output. Input order is preserved::

        >>> unique_to_each("mississippi", "missouri")
        [['p', 'p'], ['o', 'u', 'r']]

    It is assumed that the elements of each iterable are hashable.

    """
    pool = [list(it) for it in iterables]
    counts = Counter(chain.from_iterable(map(set, pool)))
    uniques = {element for element in counts if counts[element] == 1}
    return [list(filter(uniques.__contains__, it)) for it in pool]


def windowed(seq, n, fillvalue=None, step=1):
    """Return a sliding window of width *n* over the given iterable.

        >>> all_windows = windowed([1, 2, 3, 4, 5], 3)
        >>> list(all_windows)
        [(1, 2, 3), (2, 3, 4), (3, 4, 5)]

    When the window is larger than the iterable, *fillvalue* is used in place
    of missing values:

        >>> list(windowed([1, 2, 3], 4))
        [(1, 2, 3, None)]

    Each window will advance in increments of *step*:

        >>> list(windowed([1, 2, 3, 4, 5, 6], 3, fillvalue='!', step=2))
        [(1, 2, 3), (3, 4, 5), (5, 6, '!')]

    To slide into the iterable's items, use :func:`chain` to add filler items
    to the left:

        >>> iterable = [1, 2, 3, 4]
        >>> n = 3
        >>> padding = [None] * (n - 1)
        >>> list(windowed(chain(padding, iterable), 3))
        [(None, None, 1), (None, 1, 2), (1, 2, 3), (2, 3, 4)]
    """
    if n < 0:
        raise ValueError('n must be >= 0')
    if n == 0:
        yield tuple()
        return
    if step < 1:
        raise ValueError('step must be >= 1')

    window = deque(maxlen=n)
    i = n
    for _ in map(window.append, seq):
        i -= 1
        if not i:
            i = step
            yield tuple(window)

    size = len(window)
    if size == 0:
        return
    elif size < n:
        yield tuple(chain(window, repeat(fillvalue, n - size)))
    elif 0 < i < min(step, n):
        window += (fillvalue,) * i
        yield tuple(window)


def substrings(iterable):
    """Yield all of the substrings of *iterable*.

        >>> [''.join(s) for s in substrings('more')]
        ['m', 'o', 'r', 'e', 'mo', 'or', 're', 'mor', 'ore', 'more']

    Note that non-string iterables can also be subdivided.

        >>> list(substrings([0, 1, 2]))
        [(0,), (1,), (2,), (0, 1), (1, 2), (0, 1, 2)]

    """
    # The length-1 substrings
    seq = []
    for item in iter(iterable):
        seq.append(item)
        yield (item,)
    seq = tuple(seq)
    item_count = len(seq)

    # And the rest
    for n in range(2, item_count + 1):
        for i in range(item_count - n + 1):
            yield seq[i : i + n]


def substrings_indexes(seq, reverse=False):
    """Yield all substrings and their positions in *seq*

    The items yielded will be a tuple of the form ``(substr, i, j)``, where
    ``substr == seq[i:j]``.

    This function only works for iterables that support slicing, such as
    ``str`` objects.

    >>> for item in substrings_indexes('more'):
    ...    print(item)
    ('m', 0, 1)
    ('o', 1, 2)
    ('r', 2, 3)
    ('e', 3, 4)
    ('mo', 0, 2)
    ('or', 1, 3)
    ('re', 2, 4)
    ('mor', 0, 3)
    ('ore', 1, 4)
    ('more', 0, 4)

    Set *reverse* to ``True`` to yield the same items in the opposite order.


    """
    r = range(1, len(seq) + 1)
    if reverse:
        r = reversed(r)
    return (
        (seq[i : i + L], i, i + L) for L in r for i in range(len(seq) - L + 1)
    )


class bucket:
    """Wrap *iterable* and return an object that buckets it iterable into
    child iterables based on a *key* function.

        >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3']
        >>> s = bucket(iterable, key=lambda x: x[0])  # Bucket by 1st character
        >>> sorted(list(s))  # Get the keys
        ['a', 'b', 'c']
        >>> a_iterable = s['a']
        >>> next(a_iterable)
        'a1'
        >>> next(a_iterable)
        'a2'
        >>> list(s['b'])
        ['b1', 'b2', 'b3']

    The original iterable will be advanced and its items will be cached until
    they are used by the child iterables. This may require significant storage.

    By default, attempting to select a bucket to which no items belong  will
    exhaust the iterable and cache all values.
    If you specify a *validator* function, selected buckets will instead be
    checked against it.

        >>> from itertools import count
        >>> it = count(1, 2)  # Infinite sequence of odd numbers
        >>> key = lambda x: x % 10  # Bucket by last digit
        >>> validator = lambda x: x in {1, 3, 5, 7, 9}  # Odd digits only
        >>> s = bucket(it, key=key, validator=validator)
        >>> 2 in s
        False
        >>> list(s[2])
        []

    """

    def __init__(self, iterable, key, validator=None):
        self._it = iter(iterable)
        self._key = key
        self._cache = defaultdict(deque)
        self._validator = validator or (lambda x: True)

    def __contains__(self, value):
        if not self._validator(value):
            return False

        try:
            item = next(self[value])
        except StopIteration:
            return False
        else:
            self._cache[value].appendleft(item)

        return True

    def _get_values(self, value):
        """
        Helper to yield items from the parent iterator that match *value*.
        Items that don't match are stored in the local cache as they
        are encountered.
        """
        while True:
            # If we've cached some items that match the target value, emit
            # the first one and evict it from the cache.
            if self._cache[value]:
                yield self._cache[value].popleft()
            # Otherwise we need to advance the parent iterator to search for
            # a matching item, caching the rest.
            else:
                while True:
                    try:
                        item = next(self._it)
                    except StopIteration:
                        return
                    item_value = self._key(item)
                    if item_value == value:
                        yield item
                        break
                    elif self._validator(item_value):
                        self._cache[item_value].append(item)

    def __iter__(self):
        for item in self._it:
            item_value = self._key(item)
            if self._validator(item_value):
                self._cache[item_value].append(item)

        yield from self._cache.keys()

    def __getitem__(self, value):
        if not self._validator(value):
            return iter(())

        return self._get_values(value)


def spy(iterable, n=1):
    """Return a 2-tuple with a list containing the first *n* elements of
    *iterable*, and an iterator with the same items as *iterable*.
    This allows you to "look ahead" at the items in the iterable without
    advancing it.

    There is one item in the list by default:

        >>> iterable = 'abcdefg'
        >>> head, iterable = spy(iterable)
        >>> head
        ['a']
        >>> list(iterable)
        ['a', 'b', 'c', 'd', 'e', 'f', 'g']

    You may use unpacking to retrieve items instead of lists:

        >>> (head,), iterable = spy('abcdefg')
        >>> head
        'a'
        >>> (first, second), iterable = spy('abcdefg', 2)
        >>> first
        'a'
        >>> second
        'b'

    The number of items requested can be larger than the number of items in
    the iterable:

        >>> iterable = [1, 2, 3, 4, 5]
        >>> head, iterable = spy(iterable, 10)
        >>> head
        [1, 2, 3, 4, 5]
        >>> list(iterable)
        [1, 2, 3, 4, 5]

    """
    it = iter(iterable)
    head = take(n, it)

    return head.copy(), chain(head, it)


def interleave(*iterables):
    """Return a new iterable yielding from each iterable in turn,
    until the shortest is exhausted.

        >>> list(interleave([1, 2, 3], [4, 5], [6, 7, 8]))
        [1, 4, 6, 2, 5, 7]

    For a version that doesn't terminate after the shortest iterable is
    exhausted, see :func:`interleave_longest`.

    """
    return chain.from_iterable(zip(*iterables))


def interleave_longest(*iterables):
    """Return a new iterable yielding from each iterable in turn,
    skipping any that are exhausted.

        >>> list(interleave_longest([1, 2, 3], [4, 5], [6, 7, 8]))
        [1, 4, 6, 2, 5, 7, 3, 8]

    This function produces the same output as :func:`roundrobin`, but may
    perform better for some inputs (in particular when the number of iterables
    is large).

    """
    i = chain.from_iterable(zip_longest(*iterables, fillvalue=_marker))
    return (x for x in i if x is not _marker)


def interleave_evenly(iterables, lengths=None):
    """
    Interleave multiple iterables so that their elements are evenly distributed
    throughout the output sequence.

    >>> iterables = [1, 2, 3, 4, 5], ['a', 'b']
    >>> list(interleave_evenly(iterables))
    [1, 2, 'a', 3, 4, 'b', 5]

    >>> iterables = [[1, 2, 3], [4, 5], [6, 7, 8]]
    >>> list(interleave_evenly(iterables))
    [1, 6, 4, 2, 7, 3, 8, 5]

    This function requires iterables of known length. Iterables without
    ``__len__()`` can be used by manually specifying lengths with *lengths*:

    >>> from itertools import combinations, repeat
    >>> iterables = [combinations(range(4), 2), ['a', 'b', 'c']]
    >>> lengths = [4 * (4 - 1) // 2, 3]
    >>> list(interleave_evenly(iterables, lengths=lengths))
    [(0, 1), (0, 2), 'a', (0, 3), (1, 2), 'b', (1, 3), (2, 3), 'c']

    Based on Bresenham's algorithm.
    """
    if lengths is None:
        try:
            lengths = [len(it) for it in iterables]
        except TypeError:
            raise ValueError(
                'Iterable lengths could not be determined automatically. '
                'Specify them with the lengths keyword.'
            )
    elif len(iterables) != len(lengths):
        raise ValueError('Mismatching number of iterables and lengths.')

    dims = len(lengths)

    # sort iterables by length, descending
    lengths_permute = sorted(
        range(dims), key=lambda i: lengths[i], reverse=True
    )
    lengths_desc = [lengths[i] for i in lengths_permute]
    iters_desc = [iter(iterables[i]) for i in lengths_permute]

    # the longest iterable is the primary one (Bresenham: the longest
    # distance along an axis)
    delta_primary, deltas_secondary = lengths_desc[0], lengths_desc[1:]
    iter_primary, iters_secondary = iters_desc[0], iters_desc[1:]
    errors = [delta_primary // dims] * len(deltas_secondary)

    to_yield = sum(lengths)
    while to_yield:
        yield next(iter_primary)
        to_yield -= 1
        # update errors for each secondary iterable
        errors = [e - delta for e, delta in zip(errors, deltas_secondary)]

        # those iterables for which the error is negative are yielded
        # ("diagonal step" in Bresenham)
        for i, e in enumerate(errors):
            if e < 0:
                yield next(iters_secondary[i])
                to_yield -= 1
                errors[i] += delta_primary


def collapse(iterable, base_type=None, levels=None):
    """Flatten an iterable with multiple levels of nesting (e.g., a list of
    lists of tuples) into non-iterable types.

        >>> iterable = [(1, 2), ([3, 4], [[5], [6]])]
        >>> list(collapse(iterable))
        [1, 2, 3, 4, 5, 6]

    Binary and text strings are not considered iterable and
    will not be collapsed.

    To avoid collapsing other types, specify *base_type*:

        >>> iterable = ['ab', ('cd', 'ef'), ['gh', 'ij']]
        >>> list(collapse(iterable, base_type=tuple))
        ['ab', ('cd', 'ef'), 'gh', 'ij']

    Specify *levels* to stop flattening after a certain level:

    >>> iterable = [('a', ['b']), ('c', ['d'])]
    >>> list(collapse(iterable))  # Fully flattened
    ['a', 'b', 'c', 'd']
    >>> list(collapse(iterable, levels=1))  # Only one level flattened
    ['a', ['b'], 'c', ['d']]

    """

    def walk(node, level):
        if (
            ((levels is not None) and (level > levels))
            or isinstance(node, (str, bytes))
            or ((base_type is not None) and isinstance(node, base_type))
        ):
            yield node
            return

        try:
            tree = iter(node)
        except TypeError:
            yield node
            return
        else:
            for child in tree:
                yield from walk(child, level + 1)

    yield from walk(iterable, 0)


def side_effect(func, iterable, chunk_size=None, before=None, after=None):
    """Invoke *func* on each item in *iterable* (or on each *chunk_size* group
    of items) before yielding the item.

    `func` must be a function that takes a single argument. Its return value
    will be discarded.

    *before* and *after* are optional functions that take no arguments. They
    will be executed before iteration starts and after it ends, respectively.

    `side_effect` can be used for logging, updating progress bars, or anything
    that is not functionally "pure."

    Emitting a status message:

        >>> from more_itertools import consume
        >>> func = lambda item: print('Received {}'.format(item))
        >>> consume(side_effect(func, range(2)))
        Received 0
        Received 1

    Operating on chunks of items:

        >>> pair_sums = []
        >>> func = lambda chunk: pair_sums.append(sum(chunk))
        >>> list(side_effect(func, [0, 1, 2, 3, 4, 5], 2))
        [0, 1, 2, 3, 4, 5]
        >>> list(pair_sums)
        [1, 5, 9]

    Writing to a file-like object:

        >>> from io import StringIO
        >>> from more_itertools import consume
        >>> f = StringIO()
        >>> func = lambda x: print(x, file=f)
        >>> before = lambda: print(u'HEADER', file=f)
        >>> after = f.close
        >>> it = [u'a', u'b', u'c']
        >>> consume(side_effect(func, it, before=before, after=after))
        >>> f.closed
        True

    """
    try:
        if before is not None:
            before()

        if chunk_size is None:
            for item in iterable:
                func(item)
                yield item
        else:
            for chunk in chunked(iterable, chunk_size):
                func(chunk)
                yield from chunk
    finally:
        if after is not None:
            after()


def sliced(seq, n, strict=False):
    """Yield slices of length *n* from the sequence *seq*.

    >>> list(sliced((1, 2, 3, 4, 5, 6), 3))
    [(1, 2, 3), (4, 5, 6)]

    By the default, the last yielded slice will have fewer than *n* elements
    if the length of *seq* is not divisible by *n*:

    >>> list(sliced((1, 2, 3, 4, 5, 6, 7, 8), 3))
    [(1, 2, 3), (4, 5, 6), (7, 8)]

    If the length of *seq* is not divisible by *n* and *strict* is
    ``True``, then ``ValueError`` will be raised before the last
    slice is yielded.

    This function will only work for iterables that support slicing.
    For non-sliceable iterables, see :func:`chunked`.

    """
    iterator = takewhile(len, (seq[i : i + n] for i in count(0, n)))
    if strict:

        def ret():
            for _slice in iterator:
                if len(_slice) != n:
                    raise ValueError("seq is not divisible by n.")
                yield _slice

        return iter(ret())
    else:
        return iterator


def split_at(iterable, pred, maxsplit=-1, keep_separator=False):
    """Yield lists of items from *iterable*, where each list is delimited by
    an item where callable *pred* returns ``True``.

        >>> list(split_at('abcdcba', lambda x: x == 'b'))
        [['a'], ['c', 'd', 'c'], ['a']]

        >>> list(split_at(range(10), lambda n: n % 2 == 1))
        [[0], [2], [4], [6], [8], []]

    At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
    then there is no limit on the number of splits:

        >>> list(split_at(range(10), lambda n: n % 2 == 1, maxsplit=2))
        [[0], [2], [4, 5, 6, 7, 8, 9]]

    By default, the delimiting items are not included in the output.
    The include them, set *keep_separator* to ``True``.

        >>> list(split_at('abcdcba', lambda x: x == 'b', keep_separator=True))
        [['a'], ['b'], ['c', 'd', 'c'], ['b'], ['a']]

    """
    if maxsplit == 0:
        yield list(iterable)
        return

    buf = []
    it = iter(iterable)
    for item in it:
        if pred(item):
            yield buf
            if keep_separator:
                yield [item]
            if maxsplit == 1:
                yield list(it)
                return
            buf = []
            maxsplit -= 1
        else:
            buf.append(item)
    yield buf


def split_before(iterable, pred, maxsplit=-1):
    """Yield lists of items from *iterable*, where each list ends just before
    an item for which callable *pred* returns ``True``:

        >>> list(split_before('OneTwo', lambda s: s.isupper()))
        [['O', 'n', 'e'], ['T', 'w', 'o']]

        >>> list(split_before(range(10), lambda n: n % 3 == 0))
        [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

    At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
    then there is no limit on the number of splits:

        >>> list(split_before(range(10), lambda n: n % 3 == 0, maxsplit=2))
        [[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]]
    """
    if maxsplit == 0:
        yield list(iterable)
        return

    buf = []
    it = iter(iterable)
    for item in it:
        if pred(item) and buf:
            yield buf
            if maxsplit == 1:
                yield [item] + list(it)
                return
            buf = []
            maxsplit -= 1
        buf.append(item)
    if buf:
        yield buf


def split_after(iterable, pred, maxsplit=-1):
    """Yield lists of items from *iterable*, where each list ends with an
    item where callable *pred* returns ``True``:

        >>> list(split_after('one1two2', lambda s: s.isdigit()))
        [['o', 'n', 'e', '1'], ['t', 'w', 'o', '2']]

        >>> list(split_after(range(10), lambda n: n % 3 == 0))
        [[0], [1, 2, 3], [4, 5, 6], [7, 8, 9]]

    At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
    then there is no limit on the number of splits:

        >>> list(split_after(range(10), lambda n: n % 3 == 0, maxsplit=2))
        [[0], [1, 2, 3], [4, 5, 6, 7, 8, 9]]

    """
    if maxsplit == 0:
        yield list(iterable)
        return

    buf = []
    it = iter(iterable)
    for item in it:
        buf.append(item)
        if pred(item) and buf:
            yield buf
            if maxsplit == 1:
                yield list(it)
                return
            buf = []
            maxsplit -= 1
    if buf:
        yield buf


def split_when(iterable, pred, maxsplit=-1):
    """Split *iterable* into pieces based on the output of *pred*.
    *pred* should be a function that takes successive pairs of items and
    returns ``True`` if the iterable should be split in between them.

    For example, to find runs of increasing numbers, split the iterable when
    element ``i`` is larger than element ``i + 1``:

        >>> list(split_when([1, 2, 3, 3, 2, 5, 2, 4, 2], lambda x, y: x > y))
        [[1, 2, 3, 3], [2, 5], [2, 4], [2]]

    At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
    then there is no limit on the number of splits:

        >>> list(split_when([1, 2, 3, 3, 2, 5, 2, 4, 2],
        ...                 lambda x, y: x > y, maxsplit=2))
        [[1, 2, 3, 3], [2, 5], [2, 4, 2]]

    """
    if maxsplit == 0:
        yield list(iterable)
        return

    it = iter(iterable)
    try:
        cur_item = next(it)
    except StopIteration:
        return

    buf = [cur_item]
    for next_item in it:
        if pred(cur_item, next_item):
            yield buf
            if maxsplit == 1:
                yield [next_item] + list(it)
                return
            buf = []
            maxsplit -= 1

        buf.append(next_item)
        cur_item = next_item

    yield buf


def split_into(iterable, sizes):
    """Yield a list of sequential items from *iterable* of length 'n' for each
    integer 'n' in *sizes*.

        >>> list(split_into([1,2,3,4,5,6], [1,2,3]))
        [[1], [2, 3], [4, 5, 6]]

    If the sum of *sizes* is smaller than the length of *iterable*, then the
    remaining items of *iterable* will not be returned.

        >>> list(split_into([1,2,3,4,5,6], [2,3]))
        [[1, 2], [3, 4, 5]]

    If the sum of *sizes* is larger than the length of *iterable*, fewer items
    will be returned in the iteration that overruns *iterable* and further
    lists will be empty:

        >>> list(split_into([1,2,3,4], [1,2,3,4]))
        [[1], [2, 3], [4], []]

    When a ``None`` object is encountered in *sizes*, the returned list will
    contain items up to the end of *iterable* the same way that itertools.slice
    does:

        >>> list(split_into([1,2,3,4,5,6,7,8,9,0], [2,3,None]))
        [[1, 2], [3, 4, 5], [6, 7, 8, 9, 0]]

    :func:`split_into` can be useful for grouping a series of items where the
    sizes of the groups are not uniform. An example would be where in a row
    from a table, multiple columns represent elements of the same feature
    (e.g. a point represented by x,y,z) but, the format is not the same for
    all columns.
    """
    # convert the iterable argument into an iterator so its contents can
    # be consumed by islice in case it is a generator
    it = iter(iterable)

    for size in sizes:
        if size is None:
            yield list(it)
            return
        else:
            yield list(islice(it, size))


def padded(iterable, fillvalue=None, n=None, next_multiple=False):
    """Yield the elements from *iterable*, followed by *fillvalue*, such that
    at least *n* items are emitted.

        >>> list(padded([1, 2, 3], '?', 5))
        [1, 2, 3, '?', '?']

    If *next_multiple* is ``True``, *fillvalue* will be emitted until the
    number of items emitted is a multiple of *n*::

        >>> list(padded([1, 2, 3, 4], n=3, next_multiple=True))
        [1, 2, 3, 4, None, None]

    If *n* is ``None``, *fillvalue* will be emitted indefinitely.

    """
    it = iter(iterable)
    if n is None:
        yield from chain(it, repeat(fillvalue))
    elif n < 1:
        raise ValueError('n must be at least 1')
    else:
        item_count = 0
        for item in it:
            yield item
            item_count += 1

        remaining = (n - item_count) % n if next_multiple else n - item_count
        for _ in range(remaining):
            yield fillvalue


def repeat_each(iterable, n=2):
    """Repeat each element in *iterable* *n* times.

    >>> list(repeat_each('ABC', 3))
    ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C']
    """
    return chain.from_iterable(map(repeat, iterable, repeat(n)))


def repeat_last(iterable, default=None):
    """After the *iterable* is exhausted, keep yielding its last element.

        >>> list(islice(repeat_last(range(3)), 5))
        [0, 1, 2, 2, 2]

    If the iterable is empty, yield *default* forever::

        >>> list(islice(repeat_last(range(0), 42), 5))
        [42, 42, 42, 42, 42]

    """
    item = _marker
    for item in iterable:
        yield item
    final = default if item is _marker else item
    yield from repeat(final)


def distribute(n, iterable):
    """Distribute the items from *iterable* among *n* smaller iterables.

        >>> group_1, group_2 = distribute(2, [1, 2, 3, 4, 5, 6])
        >>> list(group_1)
        [1, 3, 5]
        >>> list(group_2)
        [2, 4, 6]

    If the length of *iterable* is not evenly divisible by *n*, then the
    length of the returned iterables will not be identical:

        >>> children = distribute(3, [1, 2, 3, 4, 5, 6, 7])
        >>> [list(c) for c in children]
        [[1, 4, 7], [2, 5], [3, 6]]

    If the length of *iterable* is smaller than *n*, then the last returned
    iterables will be empty:

        >>> children = distribute(5, [1, 2, 3])
        >>> [list(c) for c in children]
        [[1], [2], [3], [], []]

    This function uses :func:`itertools.tee` and may require significant
    storage. If you need the order items in the smaller iterables to match the
    original iterable, see :func:`divide`.

    """
    if n < 1:
        raise ValueError('n must be at least 1')

    children = tee(iterable, n)
    return [islice(it, index, None, n) for index, it in enumerate(children)]


def stagger(iterable, offsets=(-1, 0, 1), longest=False, fillvalue=None):
    """Yield tuples whose elements are offset from *iterable*.
    The amount by which the `i`-th item in each tuple is offset is given by
    the `i`-th item in *offsets*.

        >>> list(stagger([0, 1, 2, 3]))
        [(None, 0, 1), (0, 1, 2), (1, 2, 3)]
        >>> list(stagger(range(8), offsets=(0, 2, 4)))
        [(0, 2, 4), (1, 3, 5), (2, 4, 6), (3, 5, 7)]

    By default, the sequence will end when the final element of a tuple is the
    last item in the iterable. To continue until the first element of a tuple
    is the last item in the iterable, set *longest* to ``True``::

        >>> list(stagger([0, 1, 2, 3], longest=True))
        [(None, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, None), (3, None, None)]

    By default, ``None`` will be used to replace offsets beyond the end of the
    sequence. Specify *fillvalue* to use some other value.

    """
    children = tee(iterable, len(offsets))

    return zip_offset(
        *children, offsets=offsets, longest=longest, fillvalue=fillvalue
    )


def zip_equal(*iterables):
    """``zip`` the input *iterables* together, but raise
    ``UnequalIterablesError`` if they aren't all the same length.

        >>> it_1 = range(3)
        >>> it_2 = iter('abc')
        >>> list(zip_equal(it_1, it_2))
        [(0, 'a'), (1, 'b'), (2, 'c')]

        >>> it_1 = range(3)
        >>> it_2 = iter('abcd')
        >>> list(zip_equal(it_1, it_2)) # doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
        ...
        more_itertools.more.UnequalIterablesError: Iterables have different
        lengths

    """
    if hexversion >= 0x30A00A6:
        warnings.warn(
            (
                'zip_equal will be removed in a future version of '
                'more-itertools. Use the builtin zip function with '
                'strict=True instead.'
            ),
            DeprecationWarning,
        )

    return _zip_equal(*iterables)


def zip_offset(*iterables, offsets, longest=False, fillvalue=None):
    """``zip`` the input *iterables* together, but offset the `i`-th iterable
    by the `i`-th item in *offsets*.

        >>> list(zip_offset('0123', 'abcdef', offsets=(0, 1)))
        [('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e')]

    This can be used as a lightweight alternative to SciPy or pandas to analyze
    data sets in which some series have a lead or lag relationship.

    By default, the sequence will end when the shortest iterable is exhausted.
    To continue until the longest iterable is exhausted, set *longest* to
    ``True``.

        >>> list(zip_offset('0123', 'abcdef', offsets=(0, 1), longest=True))
        [('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e'), (None, 'f')]

    By default, ``None`` will be used to replace offsets beyond the end of the
    sequence. Specify *fillvalue* to use some other value.

    """
    if len(iterables) != len(offsets):
        raise ValueError("Number of iterables and offsets didn't match")

    staggered = []
    for it, n in zip(iterables, offsets):
        if n < 0:
            staggered.append(chain(repeat(fillvalue, -n), it))
        elif n > 0:
            staggered.append(islice(it, n, None))
        else:
            staggered.append(it)

    if longest:
        return zip_longest(*staggered, fillvalue=fillvalue)

    return zip(*staggered)


def sort_together(iterables, key_list=(0,), key=None, reverse=False):
    """Return the input iterables sorted together, with *key_list* as the
    priority for sorting. All iterables are trimmed to the length of the
    shortest one.

    This can be used like the sorting function in a spreadsheet. If each
    iterable represents a column of data, the key list determines which
    columns are used for sorting.

    By default, all iterables are sorted using the ``0``-th iterable::

        >>> iterables = [(4, 3, 2, 1), ('a', 'b', 'c', 'd')]
        >>> sort_together(iterables)
        [(1, 2, 3, 4), ('d', 'c', 'b', 'a')]

    Set a different key list to sort according to another iterable.
    Specifying multiple keys dictates how ties are broken::

        >>> iterables = [(3, 1, 2), (0, 1, 0), ('c', 'b', 'a')]
        >>> sort_together(iterables, key_list=(1, 2))
        [(2, 3, 1), (0, 0, 1), ('a', 'c', 'b')]

    To sort by a function of the elements of the iterable, pass a *key*
    function. Its arguments are the elements of the iterables corresponding to
    the key list::

        >>> names = ('a', 'b', 'c')
        >>> lengths = (1, 2, 3)
        >>> widths = (5, 2, 1)
        >>> def area(length, width):
        ...     return length * width
        >>> sort_together([names, lengths, widths], key_list=(1, 2), key=area)
        [('c', 'b', 'a'), (3, 2, 1), (1, 2, 5)]

    Set *reverse* to ``True`` to sort in descending order.

        >>> sort_together([(1, 2, 3), ('c', 'b', 'a')], reverse=True)
        [(3, 2, 1), ('a', 'b', 'c')]

    """
    if key is None:
        # if there is no key function, the key argument to sorted is an
        # itemgetter
        key_argument = itemgetter(*key_list)
    else:
        # if there is a key function, call it with the items at the offsets
        # specified by the key function as arguments
        key_list = list(key_list)
        if len(key_list) == 1:
            # if key_list contains a single item, pass the item at that offset
            # as the only argument to the key function
            key_offset = key_list[0]
            key_argument = lambda zipped_items: key(zipped_items[key_offset])
        else:
            # if key_list contains multiple items, use itemgetter to return a
            # tuple of items, which we pass as *args to the key function
            get_key_items = itemgetter(*key_list)
            key_argument = lambda zipped_items: key(
                *get_key_items(zipped_items)
            )

    return list(
        zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse))
    )


def unzip(iterable):
    """The inverse of :func:`zip`, this function disaggregates the elements
    of the zipped *iterable*.

    The ``i``-th iterable contains the ``i``-th element from each element
    of the zipped iterable. The first element is used to determine the
    length of the remaining elements.

        >>> iterable = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
        >>> letters, numbers = unzip(iterable)
        >>> list(letters)
        ['a', 'b', 'c', 'd']
        >>> list(numbers)
        [1, 2, 3, 4]

    This is similar to using ``zip(*iterable)``, but it avoids reading
    *iterable* into memory. Note, however, that this function uses
    :func:`itertools.tee` and thus may require significant storage.

    """
    head, iterable = spy(iter(iterable))
    if not head:
        # empty iterable, e.g. zip([], [], [])
        return ()
    # spy returns a one-length iterable as head
    head = head[0]
    iterables = tee(iterable, len(head))

    def itemgetter(i):
        def getter(obj):
            try:
                return obj[i]
            except IndexError:
                # basically if we have an iterable like
                # iter([(1, 2, 3), (4, 5), (6,)])
                # the second unzipped iterable would fail at the third tuple
                # since it would try to access tup[1]
                # same with the third unzipped iterable and the second tuple
                # to support these "improperly zipped" iterables,
                # we create a custom itemgetter
                # which just stops the unzipped iterables
                # at first length mismatch
                raise StopIteration

        return getter

    return tuple(map(itemgetter(i), it) for i, it in enumerate(iterables))


def divide(n, iterable):
    """Divide the elements from *iterable* into *n* parts, maintaining
    order.

        >>> group_1, group_2 = divide(2, [1, 2, 3, 4, 5, 6])
        >>> list(group_1)
        [1, 2, 3]
        >>> list(group_2)
        [4, 5, 6]

    If the length of *iterable* is not evenly divisible by *n*, then the
    length of the returned iterables will not be identical:

        >>> children = divide(3, [1, 2, 3, 4, 5, 6, 7])
        >>> [list(c) for c in children]
        [[1, 2, 3], [4, 5], [6, 7]]

    If the length of the iterable is smaller than n, then the last returned
    iterables will be empty:

        >>> children = divide(5, [1, 2, 3])
        >>> [list(c) for c in children]
        [[1], [2], [3], [], []]

    This function will exhaust the iterable before returning and may require
    significant storage. If order is not important, see :func:`distribute`,
    which does not first pull the iterable into memory.

    """
    if n < 1:
        raise ValueError('n must be at least 1')

    try:
        iterable[:0]
    except TypeError:
        seq = tuple(iterable)
    else:
        seq = iterable

    q, r = divmod(len(seq), n)

    ret = []
    stop = 0
    for i in range(1, n + 1):
        start = stop
        stop += q + 1 if i <= r else q
        ret.append(iter(seq[start:stop]))

    return ret


def always_iterable(obj, base_type=(str, bytes)):
    """If *obj* is iterable, return an iterator over its items::

        >>> obj = (1, 2, 3)
        >>> list(always_iterable(obj))
        [1, 2, 3]

    If *obj* is not iterable, return a one-item iterable containing *obj*::

        >>> obj = 1
        >>> list(always_iterable(obj))
        [1]

    If *obj* is ``None``, return an empty iterable:

        >>> obj = None
        >>> list(always_iterable(None))
        []

    By default, binary and text strings are not considered iterable::

        >>> obj = 'foo'
        >>> list(always_iterable(obj))
        ['foo']

    If *base_type* is set, objects for which ``isinstance(obj, base_type)``
    returns ``True`` won't be considered iterable.

        >>> obj = {'a': 1}
        >>> list(always_iterable(obj))  # Iterate over the dict's keys
        ['a']
        >>> list(always_iterable(obj, base_type=dict))  # Treat dicts as a unit
        [{'a': 1}]

    Set *base_type* to ``None`` to avoid any special handling and treat objects
    Python considers iterable as iterable:

        >>> obj = 'foo'
        >>> list(always_iterable(obj, base_type=None))
        ['f', 'o', 'o']
    """
    if obj is None:
        return iter(())

    if (base_type is not None) and isinstance(obj, base_type):
        return iter((obj,))

    try:
        return iter(obj)
    except TypeError:
        return iter((obj,))


def adjacent(predicate, iterable, distance=1):
    """Return an iterable over `(bool, item)` tuples where the `item` is
    drawn from *iterable* and the `bool` indicates whether
    that item satisfies the *predicate* or is adjacent to an item that does.

    For example, to find whether items are adjacent to a ``3``::

        >>> list(adjacent(lambda x: x == 3, range(6)))
        [(False, 0), (False, 1), (True, 2), (True, 3), (True, 4), (False, 5)]

    Set *distance* to change what counts as adjacent. For example, to find
    whether items are two places away from a ``3``:

        >>> list(adjacent(lambda x: x == 3, range(6), distance=2))
        [(False, 0), (True, 1), (True, 2), (True, 3), (True, 4), (True, 5)]

    This is useful for contextualizing the results of a search function.
    For example, a code comparison tool might want to identify lines that
    have changed, but also surrounding lines to give the viewer of the diff
    context.

    The predicate function will only be called once for each item in the
    iterable.

    See also :func:`groupby_transform`, which can be used with this function
    to group ranges of items with the same `bool` value.

    """
    # Allow distance=0 mainly for testing that it reproduces results with map()
    if distance < 0:
        raise ValueError('distance must be at least 0')

    i1, i2 = tee(iterable)
    padding = [False] * distance
    selected = chain(padding, map(predicate, i1), padding)
    adjacent_to_selected = map(any, windowed(selected, 2 * distance + 1))
    return zip(adjacent_to_selected, i2)


def groupby_transform(iterable, keyfunc=None, valuefunc=None, reducefunc=None):
    """An extension of :func:`itertools.groupby` that can apply transformations
    to the grouped data.

    * *keyfunc* is a function computing a key value for each item in *iterable*
    * *valuefunc* is a function that transforms the individual items from
      *iterable* after grouping
    * *reducefunc* is a function that transforms each group of items

    >>> iterable = 'aAAbBBcCC'
    >>> keyfunc = lambda k: k.upper()
    >>> valuefunc = lambda v: v.lower()
    >>> reducefunc = lambda g: ''.join(g)
    >>> list(groupby_transform(iterable, keyfunc, valuefunc, reducefunc))
    [('A', 'aaa'), ('B', 'bbb'), ('C', 'ccc')]

    Each optional argument defaults to an identity function if not specified.

    :func:`groupby_transform` is useful when grouping elements of an iterable
    using a separate iterable as the key. To do this, :func:`zip` the iterables
    and pass a *keyfunc* that extracts the first element and a *valuefunc*
    that extracts the second element::

        >>> from operator import itemgetter
        >>> keys = [0, 0, 1, 1, 1, 2, 2, 2, 3]
        >>> values = 'abcdefghi'
        >>> iterable = zip(keys, values)
        >>> grouper = groupby_transform(iterable, itemgetter(0), itemgetter(1))
        >>> [(k, ''.join(g)) for k, g in grouper]
        [(0, 'ab'), (1, 'cde'), (2, 'fgh'), (3, 'i')]

    Note that the order of items in the iterable is significant.
    Only adjacent items are grouped together, so if you don't want any
    duplicate groups, you should sort the iterable by the key function.

    """
    ret = groupby(iterable, keyfunc)
    if valuefunc:
        ret = ((k, map(valuefunc, g)) for k, g in ret)
    if reducefunc:
        ret = ((k, reducefunc(g)) for k, g in ret)

    return ret


class numeric_range(abc.Sequence, abc.Hashable):
    """An extension of the built-in ``range()`` function whose arguments can
    be any orderable numeric type.

    With only *stop* specified, *start* defaults to ``0`` and *step*
    defaults to ``1``. The output items will match the type of *stop*:

        >>> list(numeric_range(3.5))
        [0.0, 1.0, 2.0, 3.0]

    With only *start* and *stop* specified, *step* defaults to ``1``. The
    output items will match the type of *start*:

        >>> from decimal import Decimal
        >>> start = Decimal('2.1')
        >>> stop = Decimal('5.1')
        >>> list(numeric_range(start, stop))
        [Decimal('2.1'), Decimal('3.1'), Decimal('4.1')]

    With *start*, *stop*, and *step*  specified the output items will match
    the type of ``start + step``:

        >>> from fractions import Fraction
        >>> start = Fraction(1, 2)  # Start at 1/2
        >>> stop = Fraction(5, 2)  # End at 5/2
        >>> step = Fraction(1, 2)  # Count by 1/2
        >>> list(numeric_range(start, stop, step))
        [Fraction(1, 2), Fraction(1, 1), Fraction(3, 2), Fraction(2, 1)]

    If *step* is zero, ``ValueError`` is raised. Negative steps are supported:

        >>> list(numeric_range(3, -1, -1.0))
        [3.0, 2.0, 1.0, 0.0]

    Be aware of the limitations of floating point numbers; the representation
    of the yielded numbers may be surprising.

    ``datetime.datetime`` objects can be used for *start* and *stop*, if *step*
    is a ``datetime.timedelta`` object:

        >>> import datetime
        >>> start = datetime.datetime(2019, 1, 1)
        >>> stop = datetime.datetime(2019, 1, 3)
        >>> step = datetime.timedelta(days=1)
        >>> items = iter(numeric_range(start, stop, step))
        >>> next(items)
        datetime.datetime(2019, 1, 1, 0, 0)
        >>> next(items)
        datetime.datetime(2019, 1, 2, 0, 0)

    """

    _EMPTY_HASH = hash(range(0, 0))

    def __init__(self, *args):
        argc = len(args)
        if argc == 1:
            (self._stop,) = args
            self._start = type(self._stop)(0)
            self._step = type(self._stop - self._start)(1)
        elif argc == 2:
            self._start, self._stop = args
            self._step = type(self._stop - self._start)(1)
        elif argc == 3:
            self._start, self._stop, self._step = args
        elif argc == 0:
            raise TypeError(
                'numeric_range expected at least '
                '1 argument, got {}'.format(argc)
            )
        else:
            raise TypeError(
                'numeric_range expected at most '
                '3 arguments, got {}'.format(argc)
            )

        self._zero = type(self._step)(0)
        if self._step == self._zero:
            raise ValueError('numeric_range() arg 3 must not be zero')
        self._growing = self._step > self._zero
        self._init_len()

    def __bool__(self):
        if self._growing:
            return self._start < self._stop
        else:
            return self._start > self._stop

    def __contains__(self, elem):
        if self._growing:
            if self._start <= elem < self._stop:
                return (elem - self._start) % self._step == self._zero
        else:
            if self._start >= elem > self._stop:
                return (self._start - elem) % (-self._step) == self._zero

        return False

    def __eq__(self, other):
        if isinstance(other, numeric_range):
            empty_self = not bool(self)
            empty_other = not bool(other)
            if empty_self or empty_other:
                return empty_self and empty_other  # True if both empty
            else:
                return (
                    self._start == other._start
                    and self._step == other._step
                    and self._get_by_index(-1) == other._get_by_index(-1)
                )
        else:
            return False

    def __getitem__(self, key):
        if isinstance(key, int):
            return self._get_by_index(key)
        elif isinstance(key, slice):
            step = self._step if key.step is None else key.step * self._step

            if key.start is None or key.start <= -self._len:
                start = self._start
            elif key.start >= self._len:
                start = self._stop
            else:  # -self._len < key.start < self._len
                start = self._get_by_index(key.start)

            if key.stop is None or key.stop >= self._len:
                stop = self._stop
            elif key.stop <= -self._len:
                stop = self._start
            else:  # -self._len < key.stop < self._len
                stop = self._get_by_index(key.stop)

            return numeric_range(start, stop, step)
        else:
            raise TypeError(
                'numeric range indices must be '
                'integers or slices, not {}'.format(type(key).__name__)
            )

    def __hash__(self):
        if self:
            return hash((self._start, self._get_by_index(-1), self._step))
        else:
            return self._EMPTY_HASH

    def __iter__(self):
        values = (self._start + (n * self._step) for n in count())
        if self._growing:
            return takewhile(partial(gt, self._stop), values)
        else:
            return takewhile(partial(lt, self._stop), values)

    def __len__(self):
        return self._len

    def _init_len(self):
        if self._growing:
            start = self._start
            stop = self._stop
            step = self._step
        else:
            start = self._stop
            stop = self._start
            step = -self._step
        distance = stop - start
        if distance <= self._zero:
            self._len = 0
        else:  # distance > 0 and step > 0: regular euclidean division
            q, r = divmod(distance, step)
            self._len = int(q) + int(r != self._zero)

    def __reduce__(self):
        return numeric_range, (self._start, self._stop, self._step)

    def __repr__(self):
        if self._step == 1:
            return "numeric_range({}, {})".format(
                repr(self._start), repr(self._stop)
            )
        else:
            return "numeric_range({}, {}, {})".format(
                repr(self._start), repr(self._stop), repr(self._step)
            )

    def __reversed__(self):
        return iter(
            numeric_range(
                self._get_by_index(-1), self._start - self._step, -self._step
            )
        )

    def count(self, value):
        return int(value in self)

    def index(self, value):
        if self._growing:
            if self._start <= value < self._stop:
                q, r = divmod(value - self._start, self._step)
                if r == self._zero:
                    return int(q)
        else:
            if self._start >= value > self._stop:
                q, r = divmod(self._start - value, -self._step)
                if r == self._zero:
                    return int(q)

        raise ValueError("{} is not in numeric range".format(value))

    def _get_by_index(self, i):
        if i < 0:
            i += self._len
        if i < 0 or i >= self._len:
            raise IndexError("numeric range object index out of range")
        return self._start + i * self._step


def count_cycle(iterable, n=None):
    """Cycle through the items from *iterable* up to *n* times, yielding
    the number of completed cycles along with each item. If *n* is omitted the
    process repeats indefinitely.

    >>> list(count_cycle('AB', 3))
    [(0, 'A'), (0, 'B'), (1, 'A'), (1, 'B'), (2, 'A'), (2, 'B')]

    """
    iterable = tuple(iterable)
    if not iterable:
        return iter(())
    counter = count() if n is None else range(n)
    return ((i, item) for i in counter for item in iterable)


def mark_ends(iterable):
    """Yield 3-tuples of the form ``(is_first, is_last, item)``.

    >>> list(mark_ends('ABC'))
    [(True, False, 'A'), (False, False, 'B'), (False, True, 'C')]

    Use this when looping over an iterable to take special action on its first
    and/or last items:

    >>> iterable = ['Header', 100, 200, 'Footer']
    >>> total = 0
    >>> for is_first, is_last, item in mark_ends(iterable):
    ...     if is_first:
    ...         continue  # Skip the header
    ...     if is_last:
    ...         continue  # Skip the footer
    ...     total += item
    >>> print(total)
    300
    """
    it = iter(iterable)

    try:
        b = next(it)
    except StopIteration:
        return

    try:
        for i in count():
            a = b
            b = next(it)
            yield i == 0, False, a

    except StopIteration:
        yield i == 0, True, a


def locate(iterable, pred=bool, window_size=None):
    """Yield the index of each item in *iterable* for which *pred* returns
    ``True``.

    *pred* defaults to :func:`bool`, which will select truthy items:

        >>> list(locate([0, 1, 1, 0, 1, 0, 0]))
        [1, 2, 4]

    Set *pred* to a custom function to, e.g., find the indexes for a particular
    item.

        >>> list(locate(['a', 'b', 'c', 'b'], lambda x: x == 'b'))
        [1, 3]

    If *window_size* is given, then the *pred* function will be called with
    that many items. This enables searching for sub-sequences:

        >>> iterable = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
        >>> pred = lambda *args: args == (1, 2, 3)
        >>> list(locate(iterable, pred=pred, window_size=3))
        [1, 5, 9]

    Use with :func:`seekable` to find indexes and then retrieve the associated
    items:

        >>> from itertools import count
        >>> from more_itertools import seekable
        >>> source = (3 * n + 1 if (n % 2) else n // 2 for n in count())
        >>> it = seekable(source)
        >>> pred = lambda x: x > 100
        >>> indexes = locate(it, pred=pred)
        >>> i = next(indexes)
        >>> it.seek(i)
        >>> next(it)
        106

    """
    if window_size is None:
        return compress(count(), map(pred, iterable))

    if window_size < 1:
        raise ValueError('window size must be at least 1')

    it = windowed(iterable, window_size, fillvalue=_marker)
    return compress(count(), starmap(pred, it))


def longest_common_prefix(iterables):
    """Yield elements of the longest common prefix amongst given *iterables*.

    >>> ''.join(longest_common_prefix(['abcd', 'abc', 'abf']))
    'ab'

    """
    return (c[0] for c in takewhile(all_equal, zip(*iterables)))


def lstrip(iterable, pred):
    """Yield the items from *iterable*, but strip any from the beginning
    for which *pred* returns ``True``.

    For example, to remove a set of items from the start of an iterable:

        >>> iterable = (None, False, None, 1, 2, None, 3, False, None)
        >>> pred = lambda x: x in {None, False, ''}
        >>> list(lstrip(iterable, pred))
        [1, 2, None, 3, False, None]

    This function is analogous to to :func:`str.lstrip`, and is essentially
    an wrapper for :func:`itertools.dropwhile`.

    """
    return dropwhile(pred, iterable)


def rstrip(iterable, pred):
    """Yield the items from *iterable*, but strip any from the end
    for which *pred* returns ``True``.

    For example, to remove a set of items from the end of an iterable:

        >>> iterable = (None, False, None, 1, 2, None, 3, False, None)
        >>> pred = lambda x: x in {None, False, ''}
        >>> list(rstrip(iterable, pred))
        [None, False, None, 1, 2, None, 3]

    This function is analogous to :func:`str.rstrip`.

    """
    cache = []
    cache_append = cache.append
    cache_clear = cache.clear
    for x in iterable:
        if pred(x):
            cache_append(x)
        else:
            yield from cache
            cache_clear()
            yield x


def strip(iterable, pred):
    """Yield the items from *iterable*, but strip any from the
    beginning and end for which *pred* returns ``True``.

    For example, to remove a set of items from both ends of an iterable:

        >>> iterable = (None, False, None, 1, 2, None, 3, False, None)
        >>> pred = lambda x: x in {None, False, ''}
        >>> list(strip(iterable, pred))
        [1, 2, None, 3]

    This function is analogous to :func:`str.strip`.

    """
    return rstrip(lstrip(iterable, pred), pred)


class islice_extended:
    """An extension of :func:`itertools.islice` that supports negative values
    for *stop*, *start*, and *step*.

        >>> iterable = iter('abcdefgh')
        >>> list(islice_extended(iterable, -4, -1))
        ['e', 'f', 'g']

    Slices with negative values require some caching of *iterable*, but this
    function takes care to minimize the amount of memory required.

    For example, you can use a negative step with an infinite iterator:

        >>> from itertools import count
        >>> list(islice_extended(count(), 110, 99, -2))
        [110, 108, 106, 104, 102, 100]

    You can also use slice notation directly:

        >>> iterable = map(str, count())
        >>> it = islice_extended(iterable)[10:20:2]
        >>> list(it)
        ['10', '12', '14', '16', '18']

    """

    def __init__(self, iterable, *args):
        it = iter(iterable)
        if args:
            self._iterable = _islice_helper(it, slice(*args))
        else:
            self._iterable = it

    def __iter__(self):
        return self

    def __next__(self):
        return next(self._iterable)

    def __getitem__(self, key):
        if isinstance(key, slice):
            return islice_extended(_islice_helper(self._iterable, key))

        raise TypeError('islice_extended.__getitem__ argument must be a slice')


def _islice_helper(it, s):
    start = s.start
    stop = s.stop
    if s.step == 0:
        raise ValueError('step argument must be a non-zero integer or None.')
    step = s.step or 1

    if step > 0:
        start = 0 if (start is None) else start

        if start < 0:
            # Consume all but the last -start items
            cache = deque(enumerate(it, 1), maxlen=-start)
            len_iter = cache[-1][0] if cache else 0

            # Adjust start to be positive
            i = max(len_iter + start, 0)

            # Adjust stop to be positive
            if stop is None:
                j = len_iter
            elif stop >= 0:
                j = min(stop, len_iter)
            else:
                j = max(len_iter + stop, 0)

            # Slice the cache
            n = j - i
            if n <= 0:
                return

            for index, item in islice(cache, 0, n, step):
                yield item
        elif (stop is not None) and (stop < 0):
            # Advance to the start position
            next(islice(it, start, start), None)

            # When stop is negative, we have to carry -stop items while
            # iterating
            cache = deque(islice(it, -stop), maxlen=-stop)

            for index, item in enumerate(it):
                cached_item = cache.popleft()
                if index % step == 0:
                    yield cached_item
                cache.append(item)
        else:
            # When both start and stop are positive we have the normal case
            yield from islice(it, start, stop, step)
    else:
        start = -1 if (start is None) else start

        if (stop is not None) and (stop < 0):
            # Consume all but the last items
            n = -stop - 1
            cache = deque(enumerate(it, 1), maxlen=n)
            len_iter = cache[-1][0] if cache else 0

            # If start and stop are both negative they are comparable and
            # we can just slice. Otherwise we can adjust start to be negative
            # and then slice.
            if start < 0:
                i, j = start, stop
            else:
                i, j = min(start - len_iter, -1), None

            for index, item in list(cache)[i:j:step]:
                yield item
        else:
            # Advance to the stop position
            if stop is not None:
                m = stop + 1
                next(islice(it, m, m), None)

            # stop is positive, so if start is negative they are not comparable
            # and we need the rest of the items.
            if start < 0:
                i = start
                n = None
            # stop is None and start is positive, so we just need items up to
            # the start index.
            elif stop is None:
                i = None
                n = start + 1
            # Both stop and start are positive, so they are comparable.
            else:
                i = None
                n = start - stop
                if n <= 0:
                    return

            cache = list(islice(it, n))

            yield from cache[i::step]


def always_reversible(iterable):
    """An extension of :func:`reversed` that supports all iterables, not
    just those which implement the ``Reversible`` or ``Sequence`` protocols.

        >>> print(*always_reversible(x for x in range(3)))
        2 1 0

    If the iterable is already reversible, this function returns the
    result of :func:`reversed()`. If the iterable is not reversible,
    this function will cache the remaining items in the iterable and
    yield them in reverse order, which may require significant storage.
    """
    try:
        return reversed(iterable)
    except TypeError:
        return reversed(list(iterable))


def consecutive_groups(iterable, ordering=lambda x: x):
    """Yield groups of consecutive items using :func:`itertools.groupby`.
    The *ordering* function determines whether two items are adjacent by
    returning their position.

    By default, the ordering function is the identity function. This is
    suitable for finding runs of numbers:

        >>> iterable = [1, 10, 11, 12, 20, 30, 31, 32, 33, 40]
        >>> for group in consecutive_groups(iterable):
        ...     print(list(group))
        [1]
        [10, 11, 12]
        [20]
        [30, 31, 32, 33]
        [40]

    For finding runs of adjacent letters, try using the :meth:`index` method
    of a string of letters:

        >>> from string import ascii_lowercase
        >>> iterable = 'abcdfgilmnop'
        >>> ordering = ascii_lowercase.index
        >>> for group in consecutive_groups(iterable, ordering):
        ...     print(list(group))
        ['a', 'b', 'c', 'd']
        ['f', 'g']
        ['i']
        ['l', 'm', 'n', 'o', 'p']

    Each group of consecutive items is an iterator that shares it source with
    *iterable*. When an an output group is advanced, the previous group is
    no longer available unless its elements are copied (e.g., into a ``list``).

        >>> iterable = [1, 2, 11, 12, 21, 22]
        >>> saved_groups = []
        >>> for group in consecutive_groups(iterable):
        ...     saved_groups.append(list(group))  # Copy group elements
        >>> saved_groups
        [[1, 2], [11, 12], [21, 22]]

    """
    for k, g in groupby(
        enumerate(iterable), key=lambda x: x[0] - ordering(x[1])
    ):
        yield map(itemgetter(1), g)


def difference(iterable, func=sub, *, initial=None):
    """This function is the inverse of :func:`itertools.accumulate`. By default
    it will compute the first difference of *iterable* using
    :func:`operator.sub`:

        >>> from itertools import accumulate
        >>> iterable = accumulate([0, 1, 2, 3, 4])  # produces 0, 1, 3, 6, 10
        >>> list(difference(iterable))
        [0, 1, 2, 3, 4]

    *func* defaults to :func:`operator.sub`, but other functions can be
    specified. They will be applied as follows::

        A, B, C, D, ... --> A, func(B, A), func(C, B), func(D, C), ...

    For example, to do progressive division:

        >>> iterable = [1, 2, 6, 24, 120]
        >>> func = lambda x, y: x // y
        >>> list(difference(iterable, func))
        [1, 2, 3, 4, 5]

    If the *initial* keyword is set, the first element will be skipped when
    computing successive differences.

        >>> it = [10, 11, 13, 16]  # from accumulate([1, 2, 3], initial=10)
        >>> list(difference(it, initial=10))
        [1, 2, 3]

    """
    a, b = tee(iterable)
    try:
        first = [next(b)]
    except StopIteration:
        return iter([])

    if initial is not None:
        first = []

    return chain(first, map(func, b, a))


class SequenceView(Sequence):
    """Return a read-only view of the sequence object *target*.

    :class:`SequenceView` objects are analogous to Python's built-in
    "dictionary view" types. They provide a dynamic view of a sequence's items,
    meaning that when the sequence updates, so does the view.

        >>> seq = ['0', '1', '2']
        >>> view = SequenceView(seq)
        >>> view
        SequenceView(['0', '1', '2'])
        >>> seq.append('3')
        >>> view
        SequenceView(['0', '1', '2', '3'])

    Sequence views support indexing, slicing, and length queries. They act
    like the underlying sequence, except they don't allow assignment:

        >>> view[1]
        '1'
        >>> view[1:-1]
        ['1', '2']
        >>> len(view)
        4

    Sequence views are useful as an alternative to copying, as they don't
    require (much) extra storage.

    """

    def __init__(self, target):
        if not isinstance(target, Sequence):
            raise TypeError
        self._target = target

    def __getitem__(self, index):
        return self._target[index]

    def __len__(self):
        return len(self._target)

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, repr(self._target))


class seekable:
    """Wrap an iterator to allow for seeking backward and forward. This
    progressively caches the items in the source iterable so they can be
    re-visited.

    Call :meth:`seek` with an index to seek to that position in the source
    iterable.

    To "reset" an iterator, seek to ``0``:

        >>> from itertools import count
        >>> it = seekable((str(n) for n in count()))
        >>> next(it), next(it), next(it)
        ('0', '1', '2')
        >>> it.seek(0)
        >>> next(it), next(it), next(it)
        ('0', '1', '2')
        >>> next(it)
        '3'

    You can also seek forward:

        >>> it = seekable((str(n) for n in range(20)))
        >>> it.seek(10)
        >>> next(it)
        '10'
        >>> it.seek(20)  # Seeking past the end of the source isn't a problem
        >>> list(it)
        []
        >>> it.seek(0)  # Resetting works even after hitting the end
        >>> next(it), next(it), next(it)
        ('0', '1', '2')

    Call :meth:`peek` to look ahead one item without advancing the iterator:

        >>> it = seekable('1234')
        >>> it.peek()
        '1'
        >>> list(it)
        ['1', '2', '3', '4']
        >>> it.peek(default='empty')
        'empty'

    Before the iterator is at its end, calling :func:`bool` on it will return
    ``True``. After it will return ``False``:

        >>> it = seekable('5678')
        >>> bool(it)
        True
        >>> list(it)
        ['5', '6', '7', '8']
        >>> bool(it)
        False

    You may view the contents of the cache with the :meth:`elements` method.
    That returns a :class:`SequenceView`, a view that updates automatically:

        >>> it = seekable((str(n) for n in range(10)))
        >>> next(it), next(it), next(it)
        ('0', '1', '2')
        >>> elements = it.elements()
        >>> elements
        SequenceView(['0', '1', '2'])
        >>> next(it)
        '3'
        >>> elements
        SequenceView(['0', '1', '2', '3'])

    By default, the cache grows as the source iterable progresses, so beware of
    wrapping very large or infinite iterables. Supply *maxlen* to limit the
    size of the cache (this of course limits how far back you can seek).

        >>> from itertools import count
        >>> it = seekable((str(n) for n in count()), maxlen=2)
        >>> next(it), next(it), next(it), next(it)
        ('0', '1', '2', '3')
        >>> list(it.elements())
        ['2', '3']
        >>> it.seek(0)
        >>> next(it), next(it), next(it), next(it)
        ('2', '3', '4', '5')
        >>> next(it)
        '6'

    """

    def __init__(self, iterable, maxlen=None):
        self._source = iter(iterable)
        if maxlen is None:
            self._cache = []
        else:
            self._cache = deque([], maxlen)
        self._index = None

    def __iter__(self):
        return self

    def __next__(self):
        if self._index is not None:
            try:
                item = self._cache[self._index]
            except IndexError:
                self._index = None
            else:
                self._index += 1
                return item

        item = next(self._source)
        self._cache.append(item)
        return item

    def __bool__(self):
        try:
            self.peek()
        except StopIteration:
            return False
        return True

    def peek(self, default=_marker):
        try:
            peeked = next(self)
        except StopIteration:
            if default is _marker:
                raise
            return default
        if self._index is None:
            self._index = len(self._cache)
        self._index -= 1
        return peeked

    def elements(self):
        return SequenceView(self._cache)

    def seek(self, index):
        self._index = index
        remainder = index - len(self._cache)
        if remainder > 0:
            consume(self, remainder)


class run_length:
    """
    :func:`run_length.encode` compresses an iterable with run-length encoding.
    It yields groups of repeated items with the count of how many times they
    were repeated:

        >>> uncompressed = 'abbcccdddd'
        >>> list(run_length.encode(uncompressed))
        [('a', 1), ('b', 2), ('c', 3), ('d', 4)]

    :func:`run_length.decode` decompresses an iterable that was previously
    compressed with run-length encoding. It yields the items of the
    decompressed iterable:

        >>> compressed = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
        >>> list(run_length.decode(compressed))
        ['a', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd']

    """

    @staticmethod
    def encode(iterable):
        return ((k, ilen(g)) for k, g in groupby(iterable))

    @staticmethod
    def decode(iterable):
        return chain.from_iterable(repeat(k, n) for k, n in iterable)


def exactly_n(iterable, n, predicate=bool):
    """Return ``True`` if exactly ``n`` items in the iterable are ``True``
    according to the *predicate* function.

        >>> exactly_n([True, True, False], 2)
        True
        >>> exactly_n([True, True, False], 1)
        False
        >>> exactly_n([0, 1, 2, 3, 4, 5], 3, lambda x: x < 3)
        True

    The iterable will be advanced until ``n + 1`` truthy items are encountered,
    so avoid calling it on infinite iterables.

    """
    return len(take(n + 1, filter(predicate, iterable))) == n


def circular_shifts(iterable):
    """Return a list of circular shifts of *iterable*.

    >>> circular_shifts(range(4))
    [(0, 1, 2, 3), (1, 2, 3, 0), (2, 3, 0, 1), (3, 0, 1, 2)]
    """
    lst = list(iterable)
    return take(len(lst), windowed(cycle(lst), len(lst)))


def make_decorator(wrapping_func, result_index=0):
    """Return a decorator version of *wrapping_func*, which is a function that
    modifies an iterable. *result_index* is the position in that function's
    signature where the iterable goes.

    This lets you use itertools on the "production end," i.e. at function
    definition. This can augment what the function returns without changing the
    function's code.

    For example, to produce a decorator version of :func:`chunked`:

        >>> from more_itertools import chunked
        >>> chunker = make_decorator(chunked, result_index=0)
        >>> @chunker(3)
        ... def iter_range(n):
        ...     return iter(range(n))
        ...
        >>> list(iter_range(9))
        [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

    To only allow truthy items to be returned:

        >>> truth_serum = make_decorator(filter, result_index=1)
        >>> @truth_serum(bool)
        ... def boolean_test():
        ...     return [0, 1, '', ' ', False, True]
        ...
        >>> list(boolean_test())
        [1, ' ', True]

    The :func:`peekable` and :func:`seekable` wrappers make for practical
    decorators:

        >>> from more_itertools import peekable
        >>> peekable_function = make_decorator(peekable)
        >>> @peekable_function()
        ... def str_range(*args):
        ...     return (str(x) for x in range(*args))
        ...
        >>> it = str_range(1, 20, 2)
        >>> next(it), next(it), next(it)
        ('1', '3', '5')
        >>> it.peek()
        '7'
        >>> next(it)
        '7'

    """
    # See https://sites.google.com/site/bbayles/index/decorator_factory for
    # notes on how this works.
    def decorator(*wrapping_args, **wrapping_kwargs):
        def outer_wrapper(f):
            def inner_wrapper(*args, **kwargs):
                result = f(*args, **kwargs)
                wrapping_args_ = list(wrapping_args)
                wrapping_args_.insert(result_index, result)
                return wrapping_func(*wrapping_args_, **wrapping_kwargs)

            return inner_wrapper

        return outer_wrapper

    return decorator


def map_reduce(iterable, keyfunc, valuefunc=None, reducefunc=None):
    """Return a dictionary that maps the items in *iterable* to categories
    defined by *keyfunc*, transforms them with *valuefunc*, and
    then summarizes them by category with *reducefunc*.

    *valuefunc* defaults to the identity function if it is unspecified.
    If *reducefunc* is unspecified, no summarization takes place:

        >>> keyfunc = lambda x: x.upper()
        >>> result = map_reduce('abbccc', keyfunc)
        >>> sorted(result.items())
        [('A', ['a']), ('B', ['b', 'b']), ('C', ['c', 'c', 'c'])]

    Specifying *valuefunc* transforms the categorized items:

        >>> keyfunc = lambda x: x.upper()
        >>> valuefunc = lambda x: 1
        >>> result = map_reduce('abbccc', keyfunc, valuefunc)
        >>> sorted(result.items())
        [('A', [1]), ('B', [1, 1]), ('C', [1, 1, 1])]

    Specifying *reducefunc* summarizes the categorized items:

        >>> keyfunc = lambda x: x.upper()
        >>> valuefunc = lambda x: 1
        >>> reducefunc = sum
        >>> result = map_reduce('abbccc', keyfunc, valuefunc, reducefunc)
        >>> sorted(result.items())
        [('A', 1), ('B', 2), ('C', 3)]

    You may want to filter the input iterable before applying the map/reduce
    procedure:

        >>> all_items = range(30)
        >>> items = [x for x in all_items if 10 <= x <= 20]  # Filter
        >>> keyfunc = lambda x: x % 2  # Evens map to 0; odds to 1
        >>> categories = map_reduce(items, keyfunc=keyfunc)
        >>> sorted(categories.items())
        [(0, [10, 12, 14, 16, 18, 20]), (1, [11, 13, 15, 17, 19])]
        >>> summaries = map_reduce(items, keyfunc=keyfunc, reducefunc=sum)
        >>> sorted(summaries.items())
        [(0, 90), (1, 75)]

    Note that all items in the iterable are gathered into a list before the
    summarization step, which may require significant storage.

    The returned object is a :obj:`collections.defaultdict` with the
    ``default_factory`` set to ``None``, such that it behaves like a normal
    dictionary.

    """
    valuefunc = (lambda x: x) if (valuefunc is None) else valuefunc

    ret = defaultdict(list)
    for item in iterable:
        key = keyfunc(item)
        value = valuefunc(item)
        ret[key].append(value)

    if reducefunc is not None:
        for key, value_list in ret.items():
            ret[key] = reducefunc(value_list)

    ret.default_factory = None
    return ret


def rlocate(iterable, pred=bool, window_size=None):
    """Yield the index of each item in *iterable* for which *pred* returns
    ``True``, starting from the right and moving left.

    *pred* defaults to :func:`bool`, which will select truthy items:

        >>> list(rlocate([0, 1, 1, 0, 1, 0, 0]))  # Truthy at 1, 2, and 4
        [4, 2, 1]

    Set *pred* to a custom function to, e.g., find the indexes for a particular
    item:

        >>> iterable = iter('abcb')
        >>> pred = lambda x: x == 'b'
        >>> list(rlocate(iterable, pred))
        [3, 1]

    If *window_size* is given, then the *pred* function will be called with
    that many items. This enables searching for sub-sequences:

        >>> iterable = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
        >>> pred = lambda *args: args == (1, 2, 3)
        >>> list(rlocate(iterable, pred=pred, window_size=3))
        [9, 5, 1]

    Beware, this function won't return anything for infinite iterables.
    If *iterable* is reversible, ``rlocate`` will reverse it and search from
    the right. Otherwise, it will search from the left and return the results
    in reverse order.

    See :func:`locate` to for other example applications.

    """
    if window_size is None:
        try:
            len_iter = len(iterable)
            return (len_iter - i - 1 for i in locate(reversed(iterable), pred))
        except TypeError:
            pass

    return reversed(list(locate(iterable, pred, window_size)))


def replace(iterable, pred, substitutes, count=None, window_size=1):
    """Yield the items from *iterable*, replacing the items for which *pred*
    returns ``True`` with the items from the iterable *substitutes*.

        >>> iterable = [1, 1, 0, 1, 1, 0, 1, 1]
        >>> pred = lambda x: x == 0
        >>> substitutes = (2, 3)
        >>> list(replace(iterable, pred, substitutes))
        [1, 1, 2, 3, 1, 1, 2, 3, 1, 1]

    If *count* is given, the number of replacements will be limited:

        >>> iterable = [1, 1, 0, 1, 1, 0, 1, 1, 0]
        >>> pred = lambda x: x == 0
        >>> substitutes = [None]
        >>> list(replace(iterable, pred, substitutes, count=2))
        [1, 1, None, 1, 1, None, 1, 1, 0]

    Use *window_size* to control the number of items passed as arguments to
    *pred*. This allows for locating and replacing subsequences.

        >>> iterable = [0, 1, 2, 5, 0, 1, 2, 5]
        >>> window_size = 3
        >>> pred = lambda *args: args == (0, 1, 2)  # 3 items passed to pred
        >>> substitutes = [3, 4] # Splice in these items
        >>> list(replace(iterable, pred, substitutes, window_size=window_size))
        [3, 4, 5, 3, 4, 5]

    """
    if window_size < 1:
        raise ValueError('window_size must be at least 1')

    # Save the substitutes iterable, since it's used more than once
    substitutes = tuple(substitutes)

    # Add padding such that the number of windows matches the length of the
    # iterable
    it = chain(iterable, [_marker] * (window_size - 1))
    windows = windowed(it, window_size)

    n = 0
    for w in windows:
        # If the current window matches our predicate (and we haven't hit
        # our maximum number of replacements), splice in the substitutes
        # and then consume the following windows that overlap with this one.
        # For example, if the iterable is (0, 1, 2, 3, 4...)
        # and the window size is 2, we have (0, 1), (1, 2), (2, 3)...
        # If the predicate matches on (0, 1), we need to zap (0, 1) and (1, 2)
        if pred(*w):
            if (count is None) or (n < count):
                n += 1
                yield from substitutes
                consume(windows, window_size - 1)
                continue

        # If there was no match (or we've reached the replacement limit),
        # yield the first item from the window.
        if w and (w[0] is not _marker):
            yield w[0]


def partitions(iterable):
    """Yield all possible order-preserving partitions of *iterable*.

    >>> iterable = 'abc'
    >>> for part in partitions(iterable):
    ...     print([''.join(p) for p in part])
    ['abc']
    ['a', 'bc']
    ['ab', 'c']
    ['a', 'b', 'c']

    This is unrelated to :func:`partition`.

    """
    sequence = list(iterable)
    n = len(sequence)
    for i in powerset(range(1, n)):
        yield [sequence[i:j] for i, j in zip((0,) + i, i + (n,))]


def set_partitions(iterable, k=None):
    """
    Yield the set partitions of *iterable* into *k* parts. Set partitions are
    not order-preserving.

    >>> iterable = 'abc'
    >>> for part in set_partitions(iterable, 2):
    ...     print([''.join(p) for p in part])
    ['a', 'bc']
    ['ab', 'c']
    ['b', 'ac']


    If *k* is not given, every set partition is generated.

    >>> iterable = 'abc'
    >>> for part in set_partitions(iterable):
    ...     print([''.join(p) for p in part])
    ['abc']
    ['a', 'bc']
    ['ab', 'c']
    ['b', 'ac']
    ['a', 'b', 'c']

    """
    L = list(iterable)
    n = len(L)
    if k is not None:
        if k < 1:
            raise ValueError(
                "Can't partition in a negative or zero number of groups"
            )
        elif k > n:
            return

    def set_partitions_helper(L, k):
        n = len(L)
        if k == 1:
            yield [L]
        elif n == k:
            yield [[s] for s in L]
        else:
            e, *M = L
            for p in set_partitions_helper(M, k - 1):
                yield [[e], *p]
            for p in set_partitions_helper(M, k):
                for i in range(len(p)):
                    yield p[:i] + [[e] + p[i]] + p[i + 1 :]

    if k is None:
        for k in range(1, n + 1):
            yield from set_partitions_helper(L, k)
    else:
        yield from set_partitions_helper(L, k)


class time_limited:
    """
    Yield items from *iterable* until *limit_seconds* have passed.
    If the time limit expires before all items have been yielded, the
    ``timed_out`` parameter will be set to ``True``.

    >>> from time import sleep
    >>> def generator():
    ...     yield 1
    ...     yield 2
    ...     sleep(0.2)
    ...     yield 3
    >>> iterable = time_limited(0.1, generator())
    >>> list(iterable)
    [1, 2]
    >>> iterable.timed_out
    True

    Note that the time is checked before each item is yielded, and iteration
    stops if  the time elapsed is greater than *limit_seconds*. If your time
    limit is 1 second, but it takes 2 seconds to generate the first item from
    the iterable, the function will run for 2 seconds and not yield anything.

    """

    def __init__(self, limit_seconds, iterable):
        if limit_seconds < 0:
            raise ValueError('limit_seconds must be positive')
        self.limit_seconds = limit_seconds
        self._iterable = iter(iterable)
        self._start_time = monotonic()
        self.timed_out = False

    def __iter__(self):
        return self

    def __next__(self):
        item = next(self._iterable)
        if monotonic() - self._start_time > self.limit_seconds:
            self.timed_out = True
            raise StopIteration

        return item


def only(iterable, default=None, too_long=None):
    """If *iterable* has only one item, return it.
    If it has zero items, return *default*.
    If it has more than one item, raise the exception given by *too_long*,
    which is ``ValueError`` by default.

    >>> only([], default='missing')
    'missing'
    >>> only([1])
    1
    >>> only([1, 2])  # doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ...
    ValueError: Expected exactly one item in iterable, but got 1, 2,
     and perhaps more.'
    >>> only([1, 2], too_long=TypeError)  # doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ...
    TypeError

    Note that :func:`only` attempts to advance *iterable* twice to ensure there
    is only one item.  See :func:`spy` or :func:`peekable` to check
    iterable contents less destructively.
    """
    it = iter(iterable)
    first_value = next(it, default)

    try:
        second_value = next(it)
    except StopIteration:
        pass
    else:
        msg = (
            'Expected exactly one item in iterable, but got {!r}, {!r}, '
            'and perhaps more.'.format(first_value, second_value)
        )
        raise too_long or ValueError(msg)

    return first_value


class _IChunk:
    def __init__(self, iterable, n):
        self._it = islice(iterable, n)
        self._cache = deque()

    def fill_cache(self):
        self._cache.extend(self._it)

    def __iter__(self):
        return self

    def __next__(self):
        try:
            return next(self._it)
        except StopIteration:
            if self._cache:
                return self._cache.popleft()
            else:
                raise


def ichunked(iterable, n):
    """Break *iterable* into sub-iterables with *n* elements each.
    :func:`ichunked` is like :func:`chunked`, but it yields iterables
    instead of lists.

    If the sub-iterables are read in order, the elements of *iterable*
    won't be stored in memory.
    If they are read out of order, :func:`itertools.tee` is used to cache
    elements as necessary.

    >>> from itertools import count
    >>> all_chunks = ichunked(count(), 4)
    >>> c_1, c_2, c_3 = next(all_chunks), next(all_chunks), next(all_chunks)
    >>> list(c_2)  # c_1's elements have been cached; c_3's haven't been
    [4, 5, 6, 7]
    >>> list(c_1)
    [0, 1, 2, 3]
    >>> list(c_3)
    [8, 9, 10, 11]

    """
    source = peekable(iter(iterable))
    ichunk_marker = object()
    while True:
        # Check to see whether we're at the end of the source iterable
        item = source.peek(ichunk_marker)
        if item is ichunk_marker:
            return

        chunk = _IChunk(source, n)
        yield chunk

        # Advance the source iterable and fill previous chunk's cache
        chunk.fill_cache()


def iequals(*iterables):
    """Return ``True`` if all given *iterables* are equal to each other,
    which means that they contain the same elements in the same order.

    The function is useful for comparing iterables of different data types
    or iterables that do not support equality checks.

    >>> iequals("abc", ['a', 'b', 'c'], ('a', 'b', 'c'), iter("abc"))
    True

    >>> iequals("abc", "acb")
    False

    Not to be confused with :func:`all_equals`, which checks whether all
    elements of iterable are equal to each other.

    """
    return all(map(all_equal, zip_longest(*iterables, fillvalue=object())))


def distinct_combinations(iterable, r):
    """Yield the distinct combinations of *r* items taken from *iterable*.

        >>> list(distinct_combinations([0, 0, 1], 2))
        [(0, 0), (0, 1)]

    Equivalent to ``set(combinations(iterable))``, except duplicates are not
    generated and thrown away. For larger input sequences this is much more
    efficient.

    """
    if r < 0:
        raise ValueError('r must be non-negative')
    elif r == 0:
        yield ()
        return
    pool = tuple(iterable)
    generators = [unique_everseen(enumerate(pool), key=itemgetter(1))]
    current_combo = [None] * r
    level = 0
    while generators:
        try:
            cur_idx, p = next(generators[-1])
        except StopIteration:
            generators.pop()
            level -= 1
            continue
        current_combo[level] = p
        if level + 1 == r:
            yield tuple(current_combo)
        else:
            generators.append(
                unique_everseen(
                    enumerate(pool[cur_idx + 1 :], cur_idx + 1),
                    key=itemgetter(1),
                )
            )
            level += 1


def filter_except(validator, iterable, *exceptions):
    """Yield the items from *iterable* for which the *validator* function does
    not raise one of the specified *exceptions*.

    *validator* is called for each item in *iterable*.
    It should be a function that accepts one argument and raises an exception
    if that item is not valid.

    >>> iterable = ['1', '2', 'three', '4', None]
    >>> list(filter_except(int, iterable, ValueError, TypeError))
    ['1', '2', '4']

    If an exception other than one given by *exceptions* is raised by
    *validator*, it is raised like normal.
    """
    for item in iterable:
        try:
            validator(item)
        except exceptions:
            pass
        else:
            yield item


def map_except(function, iterable, *exceptions):
    """Transform each item from *iterable* with *function* and yield the
    result, unless *function* raises one of the specified *exceptions*.

    *function* is called to transform each item in *iterable*.
    It should accept one argument.

    >>> iterable = ['1', '2', 'three', '4', None]
    >>> list(map_except(int, iterable, ValueError, TypeError))
    [1, 2, 4]

    If an exception other than one given by *exceptions* is raised by
    *function*, it is raised like normal.
    """
    for item in iterable:
        try:
            yield function(item)
        except exceptions:
            pass


def map_if(iterable, pred, func, func_else=lambda x: x):
    """Evaluate each item from *iterable* using *pred*. If the result is
    equivalent to ``True``, transform the item with *func* and yield it.
    Otherwise, transform the item with *func_else* and yield it.

    *pred*, *func*, and *func_else* should each be functions that accept
    one argument. By default, *func_else* is the identity function.

    >>> from math import sqrt
    >>> iterable = list(range(-5, 5))
    >>> iterable
    [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
    >>> list(map_if(iterable, lambda x: x > 3, lambda x: 'toobig'))
    [-5, -4, -3, -2, -1, 0, 1, 2, 3, 'toobig']
    >>> list(map_if(iterable, lambda x: x >= 0,
    ... lambda x: f'{sqrt(x):.2f}', lambda x: None))
    [None, None, None, None, None, '0.00', '1.00', '1.41', '1.73', '2.00']
    """
    for item in iterable:
        yield func(item) if pred(item) else func_else(item)


def _sample_unweighted(iterable, k):
    # Implementation of "Algorithm L" from the 1994 paper by Kim-Hung Li:
    # "Reservoir-Sampling Algorithms of Time Complexity O(n(1+log(N/n)))".

    # Fill up the reservoir (collection of samples) with the first `k` samples
    reservoir = take(k, iterable)

    # Generate random number that's the largest in a sample of k U(0,1) numbers
    # Largest order statistic: https://en.wikipedia.org/wiki/Order_statistic
    W = exp(log(random()) / k)

    # The number of elements to skip before changing the reservoir is a random
    # number with a geometric distribution. Sample it using random() and logs.
    next_index = k + floor(log(random()) / log(1 - W))

    for index, element in enumerate(iterable, k):

        if index == next_index:
            reservoir[randrange(k)] = element
            # The new W is the largest in a sample of k U(0, `old_W`) numbers
            W *= exp(log(random()) / k)
            next_index += floor(log(random()) / log(1 - W)) + 1

    return reservoir


def _sample_weighted(iterable, k, weights):
    # Implementation of "A-ExpJ" from the 2006 paper by Efraimidis et al. :
    # "Weighted random sampling with a reservoir".

    # Log-transform for numerical stability for weights that are small/large
    weight_keys = (log(random()) / weight for weight in weights)

    # Fill up the reservoir (collection of samples) with the first `k`
    # weight-keys and elements, then heapify the list.
    reservoir = take(k, zip(weight_keys, iterable))
    heapify(reservoir)

    # The number of jumps before changing the reservoir is a random variable
    # with an exponential distribution. Sample it using random() and logs.
    smallest_weight_key, _ = reservoir[0]
    weights_to_skip = log(random()) / smallest_weight_key

    for weight, element in zip(weights, iterable):
        if weight >= weights_to_skip:
            # The notation here is consistent with the paper, but we store
            # the weight-keys in log-space for better numerical stability.
            smallest_weight_key, _ = reservoir[0]
            t_w = exp(weight * smallest_weight_key)
            r_2 = uniform(t_w, 1)  # generate U(t_w, 1)
            weight_key = log(r_2) / weight
            heapreplace(reservoir, (weight_key, element))
            smallest_weight_key, _ = reservoir[0]
            weights_to_skip = log(random()) / smallest_weight_key
        else:
            weights_to_skip -= weight

    # Equivalent to [element for weight_key, element in sorted(reservoir)]
    return [heappop(reservoir)[1] for _ in range(k)]


def sample(iterable, k, weights=None):
    """Return a *k*-length list of elements chosen (without replacement)
    from the *iterable*. Like :func:`random.sample`, but works on iterables
    of unknown length.

    >>> iterable = range(100)
    >>> sample(iterable, 5)  # doctest: +SKIP
    [81, 60, 96, 16, 4]

    An iterable with *weights* may also be given:

    >>> iterable = range(100)
    >>> weights = (i * i + 1 for i in range(100))
    >>> sampled = sample(iterable, 5, weights=weights)  # doctest: +SKIP
    [79, 67, 74, 66, 78]

    The algorithm can also be used to generate weighted random permutations.
    The relative weight of each item determines the probability that it
    appears late in the permutation.

    >>> data = "abcdefgh"
    >>> weights = range(1, len(data) + 1)
    >>> sample(data, k=len(data), weights=weights)  # doctest: +SKIP
    ['c', 'a', 'b', 'e', 'g', 'd', 'h', 'f']
    """
    if k == 0:
        return []

    iterable = iter(iterable)
    if weights is None:
        return _sample_unweighted(iterable, k)
    else:
        weights = iter(weights)
        return _sample_weighted(iterable, k, weights)


def is_sorted(iterable, key=None, reverse=False, strict=False):
    """Returns ``True`` if the items of iterable are in sorted order, and
    ``False`` otherwise. *key* and *reverse* have the same meaning that they do
    in the built-in :func:`sorted` function.

    >>> is_sorted(['1', '2', '3', '4', '5'], key=int)
    True
    >>> is_sorted([5, 4, 3, 1, 2], reverse=True)
    False

    If *strict*, tests for strict sorting, that is, returns ``False`` if equal
    elements are found:

    >>> is_sorted([1, 2, 2])
    True
    >>> is_sorted([1, 2, 2], strict=True)
    False

    The function returns ``False`` after encountering the first out-of-order
    item. If there are no out-of-order items, the iterable is exhausted.
    """

    compare = (le if reverse else ge) if strict else (lt if reverse else gt)
    it = iterable if key is None else map(key, iterable)
    return not any(starmap(compare, pairwise(it)))


class AbortThread(BaseException):
    pass


class callback_iter:
    """Convert a function that uses callbacks to an iterator.

    Let *func* be a function that takes a `callback` keyword argument.
    For example:

    >>> def func(callback=None):
    ...     for i, c in [(1, 'a'), (2, 'b'), (3, 'c')]:
    ...         if callback:
    ...             callback(i, c)
    ...     return 4


    Use ``with callback_iter(func)`` to get an iterator over the parameters
    that are delivered to the callback.

    >>> with callback_iter(func) as it:
    ...     for args, kwargs in it:
    ...         print(args)
    (1, 'a')
    (2, 'b')
    (3, 'c')

    The function will be called in a background thread. The ``done`` property
    indicates whether it has completed execution.

    >>> it.done
    True

    If it completes successfully, its return value will be available
    in the ``result`` property.

    >>> it.result
    4

    Notes:

    * If the function uses some keyword argument besides ``callback``, supply
      *callback_kwd*.
    * If it finished executing, but raised an exception, accessing the
      ``result`` property will raise the same exception.
    * If it hasn't finished executing, accessing the ``result``
      property from within the ``with`` block will raise ``RuntimeError``.
    * If it hasn't finished executing, accessing the ``result`` property from
      outside the ``with`` block will raise a
      ``more_itertools.AbortThread`` exception.
    * Provide *wait_seconds* to adjust how frequently the it is polled for
      output.

    """

    def __init__(self, func, callback_kwd='callback', wait_seconds=0.1):
        self._func = func
        self._callback_kwd = callback_kwd
        self._aborted = False
        self._future = None
        self._wait_seconds = wait_seconds
        # Lazily import concurrent.future
        self._executor = __import__(
        ).futures.__import__("concurrent.futures").futures.ThreadPoolExecutor(max_workers=1)
        self._iterator = self._reader()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self._aborted = True
        self._executor.shutdown()

    def __iter__(self):
        return self

    def __next__(self):
        return next(self._iterator)

    @property
    def done(self):
        if self._future is None:
            return False
        return self._future.done()

    @property
    def result(self):
        if not self.done:
            raise RuntimeError('Function has not yet completed')

        return self._future.result()

    def _reader(self):
        q = Queue()

        def callback(*args, **kwargs):
            if self._aborted:
                raise AbortThread('canceled by user')

            q.put((args, kwargs))

        self._future = self._executor.submit(
            self._func, **{self._callback_kwd: callback}
        )

        while True:
            try:
                item = q.get(timeout=self._wait_seconds)
            except Empty:
                pass
            else:
                q.task_done()
                yield item

            if self._future.done():
                break

        remaining = []
        while True:
            try:
                item = q.get_nowait()
            except Empty:
                break
            else:
                q.task_done()
                remaining.append(item)
        q.join()
        yield from remaining


def windowed_complete(iterable, n):
    """
    Yield ``(beginning, middle, end)`` tuples, where:

    * Each ``middle`` has *n* items from *iterable*
    * Each ``beginning`` has the items before the ones in ``middle``
    * Each ``end`` has the items after the ones in ``middle``

    >>> iterable = range(7)
    >>> n = 3
    >>> for beginning, middle, end in windowed_complete(iterable, n):
    ...     print(beginning, middle, end)
    () (0, 1, 2) (3, 4, 5, 6)
    (0,) (1, 2, 3) (4, 5, 6)
    (0, 1) (2, 3, 4) (5, 6)
    (0, 1, 2) (3, 4, 5) (6,)
    (0, 1, 2, 3) (4, 5, 6) ()

    Note that *n* must be at least 0 and most equal to the length of
    *iterable*.

    This function will exhaust the iterable and may require significant
    storage.
    """
    if n < 0:
        raise ValueError('n must be >= 0')

    seq = tuple(iterable)
    size = len(seq)

    if n > size:
        raise ValueError('n must be <= len(seq)')

    for i in range(size - n + 1):
        beginning = seq[:i]
        middle = seq[i : i + n]
        end = seq[i + n :]
        yield beginning, middle, end


def all_unique(iterable, key=None):
    """
    Returns ``True`` if all the elements of *iterable* are unique (no two
    elements are equal).

        >>> all_unique('ABCB')
        False

    If a *key* function is specified, it will be used to make comparisons.

        >>> all_unique('ABCb')
        True
        >>> all_unique('ABCb', str.lower)
        False

    The function returns as soon as the first non-unique element is
    encountered. Iterables with a mix of hashable and unhashable items can
    be used, but the function will be slower for unhashable items.
    """
    seenset = set()
    seenset_add = seenset.add
    seenlist = []
    seenlist_add = seenlist.append
    for element in map(key, iterable) if key else iterable:
        try:
            if element in seenset:
                return False
            seenset_add(element)
        except TypeError:
            if element in seenlist:
                return False
            seenlist_add(element)
    return True


def nth_product(index, *args):
    """Equivalent to ``list(product(*args))[index]``.

    The products of *args* can be ordered lexicographically.
    :func:`nth_product` computes the product at sort position *index* without
    computing the previous products.

        >>> nth_product(8, range(2), range(2), range(2), range(2))
        (1, 0, 0, 0)

    ``IndexError`` will be raised if the given *index* is invalid.
    """
    pools = list(map(tuple, reversed(args)))
    ns = list(map(len, pools))

    c = reduce(mul, ns)

    if index < 0:
        index += c

    if not 0 <= index < c:
        raise IndexError

    result = []
    for pool, n in zip(pools, ns):
        result.append(pool[index % n])
        index //= n

    return tuple(reversed(result))


def nth_permutation(iterable, r, index):
    """Equivalent to ``list(permutations(iterable, r))[index]```

    The subsequences of *iterable* that are of length *r* where order is
    important can be ordered lexicographically. :func:`nth_permutation`
    computes the subsequence at sort position *index* directly, without
    computing the previous subsequences.

        >>> nth_permutation('ghijk', 2, 5)
        ('h', 'i')

    ``ValueError`` will be raised If *r* is negative or greater than the length
    of *iterable*.
    ``IndexError`` will be raised if the given *index* is invalid.
    """
    pool = list(iterable)
    n = len(pool)

    if r is None or r == n:
        r, c = n, factorial(n)
    elif not 0 <= r < n:
        raise ValueError
    else:
        c = factorial(n) // factorial(n - r)

    if index < 0:
        index += c

    if not 0 <= index < c:
        raise IndexError

    if c == 0:
        return tuple()

    result = [0] * r
    q = index * factorial(n) // c if r < n else index
    for d in range(1, n + 1):
        q, i = divmod(q, d)
        if 0 <= n - d < r:
            result[n - d] = i
        if q == 0:
            break

    return tuple(map(pool.pop, result))


def value_chain(*args):
    """Yield all arguments passed to the function in the same order in which
    they were passed. If an argument itself is iterable then iterate over its
    values.

        >>> list(value_chain(1, 2, 3, [4, 5, 6]))
        [1, 2, 3, 4, 5, 6]

    Binary and text strings are not considered iterable and are emitted
    as-is:

        >>> list(value_chain('12', '34', ['56', '78']))
        ['12', '34', '56', '78']


    Multiple levels of nesting are not flattened.

    """
    for value in args:
        if isinstance(value, (str, bytes)):
            yield value
            continue
        try:
            yield from value
        except TypeError:
            yield value


def product_index(element, *args):
    """Equivalent to ``list(product(*args)).index(element)``

    The products of *args* can be ordered lexicographically.
    :func:`product_index` computes the first index of *element* without
    computing the previous products.

        >>> product_index([8, 2], range(10), range(5))
        42

    ``ValueError`` will be raised if the given *element* isn't in the product
    of *args*.
    """
    index = 0

    for x, pool in zip_longest(element, args, fillvalue=_marker):
        if x is _marker or pool is _marker:
            raise ValueError('element is not a product of args')

        pool = tuple(pool)
        index = index * len(pool) + pool.index(x)

    return index


def combination_index(element, iterable):
    """Equivalent to ``list(combinations(iterable, r)).index(element)``

    The subsequences of *iterable* that are of length *r* can be ordered
    lexicographically. :func:`combination_index` computes the index of the
    first *element*, without computing the previous combinations.

        >>> combination_index('adf', 'abcdefg')
        10

    ``ValueError`` will be raised if the given *element* isn't one of the
    combinations of *iterable*.
    """
    element = enumerate(element)
    k, y = next(element, (None, None))
    if k is None:
        return 0

    indexes = []
    pool = enumerate(iterable)
    for n, x in pool:
        if x == y:
            indexes.append(n)
            tmp, y = next(element, (None, None))
            if tmp is None:
                break
            else:
                k = tmp
    else:
        raise ValueError('element is not a combination of iterable')

    n, _ = last(pool, default=(n, None))

    # Python versions below 3.8 don't have math.comb
    index = 1
    for i, j in enumerate(reversed(indexes), start=1):
        j = n - j
        if i <= j:
            index += factorial(j) // (factorial(i) * factorial(j - i))

    return factorial(n + 1) // (factorial(k + 1) * factorial(n - k)) - index


def permutation_index(element, iterable):
    """Equivalent to ``list(permutations(iterable, r)).index(element)```

    The subsequences of *iterable* that are of length *r* where order is
    important can be ordered lexicographically. :func:`permutation_index`
    computes the index of the first *element* directly, without computing
    the previous permutations.

        >>> permutation_index([1, 3, 2], range(5))
        19

    ``ValueError`` will be raised if the given *element* isn't one of the
    permutations of *iterable*.
    """
    index = 0
    pool = list(iterable)
    for i, x in zip(range(len(pool), -1, -1), element):
        r = pool.index(x)
        index = index * i + r
        del pool[r]

    return index


class countable:
    """Wrap *iterable* and keep a count of how many items have been consumed.

    The ``items_seen`` attribute starts at ``0`` and increments as the iterable
    is consumed:

        >>> iterable = map(str, range(10))
        >>> it = countable(iterable)
        >>> it.items_seen
        0
        >>> next(it), next(it)
        ('0', '1')
        >>> list(it)
        ['2', '3', '4', '5', '6', '7', '8', '9']
        >>> it.items_seen
        10
    """

    def __init__(self, iterable):
        self._it = iter(iterable)
        self.items_seen = 0

    def __iter__(self):
        return self

    def __next__(self):
        item = next(self._it)
        self.items_seen += 1

        return item


def chunked_even(iterable, n):
    """Break *iterable* into lists of approximately length *n*.
    Items are distributed such the lengths of the lists differ by at most
    1 item.

    >>> iterable = [1, 2, 3, 4, 5, 6, 7]
    >>> n = 3
    >>> list(chunked_even(iterable, n))  # List lengths: 3, 2, 2
    [[1, 2, 3], [4, 5], [6, 7]]
    >>> list(chunked(iterable, n))  # List lengths: 3, 3, 1
    [[1, 2, 3], [4, 5, 6], [7]]

    """

    len_method = getattr(iterable, '__len__', None)

    if len_method is None:
        return _chunked_even_online(iterable, n)
    else:
        return _chunked_even_finite(iterable, len_method(), n)


def _chunked_even_online(iterable, n):
    buffer = []
    maxbuf = n + (n - 2) * (n - 1)
    for x in iterable:
        buffer.append(x)
        if len(buffer) == maxbuf:
            yield buffer[:n]
            buffer = buffer[n:]
    yield from _chunked_even_finite(buffer, len(buffer), n)


def _chunked_even_finite(iterable, N, n):
    if N < 1:
        return

    # Lists are either size `full_size <= n` or `partial_size = full_size - 1`
    q, r = divmod(N, n)
    num_lists = q + (1 if r > 0 else 0)
    q, r = divmod(N, num_lists)
    full_size = q + (1 if r > 0 else 0)
    partial_size = full_size - 1
    num_full = N - partial_size * num_lists
    num_partial = num_lists - num_full

    buffer = []
    iterator = iter(iterable)

    # Yield num_full lists of full_size
    for x in iterator:
        buffer.append(x)
        if len(buffer) == full_size:
            yield buffer
            buffer = []
            num_full -= 1
            if num_full <= 0:
                break

    # Yield num_partial lists of partial_size
    for x in iterator:
        buffer.append(x)
        if len(buffer) == partial_size:
            yield buffer
            buffer = []
            num_partial -= 1


def zip_broadcast(*objects, scalar_types=(str, bytes), strict=False):
    """A version of :func:`zip` that "broadcasts" any scalar
    (i.e., non-iterable) items into output tuples.

    >>> iterable_1 = [1, 2, 3]
    >>> iterable_2 = ['a', 'b', 'c']
    >>> scalar = '_'
    >>> list(zip_broadcast(iterable_1, iterable_2, scalar))
    [(1, 'a', '_'), (2, 'b', '_'), (3, 'c', '_')]

    The *scalar_types* keyword argument determines what types are considered
    scalar. It is set to ``(str, bytes)`` by default. Set it to ``None`` to
    treat strings and byte strings as iterable:

    >>> list(zip_broadcast('abc', 0, 'xyz', scalar_types=None))
    [('a', 0, 'x'), ('b', 0, 'y'), ('c', 0, 'z')]

    If the *strict* keyword argument is ``True``, then
    ``UnequalIterablesError`` will be raised if any of the iterables have
    different lengths.
    """

    def is_scalar(obj):
        if scalar_types and isinstance(obj, scalar_types):
            return True
        try:
            iter(obj)
        except TypeError:
            return True
        else:
            return False

    size = len(objects)
    if not size:
        return

    iterables, iterable_positions = [], []
    scalars, scalar_positions = [], []
    for i, obj in enumerate(objects):
        if is_scalar(obj):
            scalars.append(obj)
            scalar_positions.append(i)
        else:
            iterables.append(iter(obj))
            iterable_positions.append(i)

    if len(scalars) == size:
        yield tuple(objects)
        return

    zipper = _zip_equal if strict else zip
    for item in zipper(*iterables):
        new_item = [None] * size

        for i, elem in zip(iterable_positions, item):
            new_item[i] = elem

        for i, elem in zip(scalar_positions, scalars):
            new_item[i] = elem

        yield tuple(new_item)


def unique_in_window(iterable, n, key=None):
    """Yield the items from *iterable* that haven't been seen recently.
    *n* is the size of the lookback window.

        >>> iterable = [0, 1, 0, 2, 3, 0]
        >>> n = 3
        >>> list(unique_in_window(iterable, n))
        [0, 1, 2, 3, 0]

    The *key* function, if provided, will be used to determine uniqueness:

        >>> list(unique_in_window('abAcda', 3, key=lambda x: x.lower()))
        ['a', 'b', 'c', 'd', 'a']

    The items in *iterable* must be hashable.

    """
    if n <= 0:
        raise ValueError('n must be greater than 0')

    window = deque(maxlen=n)
    uniques = set()
    use_key = key is not None

    for item in iterable:
        k = key(item) if use_key else item
        if k in uniques:
            continue

        if len(uniques) == n:
            uniques.discard(window[0])

        uniques.add(k)
        window.append(k)

        yield item


def duplicates_everseen(iterable, key=None):
    """Yield duplicate elements after their first appearance.

    >>> list(duplicates_everseen('mississippi'))
    ['s', 'i', 's', 's', 'i', 'p', 'i']
    >>> list(duplicates_everseen('AaaBbbCccAaa', str.lower))
    ['a', 'a', 'b', 'b', 'c', 'c', 'A', 'a', 'a']

    This function is analagous to :func:`unique_everseen` and is subject to
    the same performance considerations.

    """
    seen_set = set()
    seen_list = []
    use_key = key is not None

    for element in iterable:
        k = key(element) if use_key else element
        try:
            if k not in seen_set:
                seen_set.add(k)
            else:
                yield element
        except TypeError:
            if k not in seen_list:
                seen_list.append(k)
            else:
                yield element


def duplicates_justseen(iterable, key=None):
    """Yields serially-duplicate elements after their first appearance.

    >>> list(duplicates_justseen('mississippi'))
    ['s', 's', 'p']
    >>> list(duplicates_justseen('AaaBbbCccAaa', str.lower))
    ['a', 'a', 'b', 'b', 'c', 'c', 'a', 'a']

    This function is analagous to :func:`unique_justseen`.

    """
    return flatten(
        map(
            lambda group_tuple: islice_extended(group_tuple[1])[1:],
            groupby(iterable, key),
        )
    )


def minmax(iterable_or_value, *others, key=None, default=_marker):
    """Returns both the smallest and largest items in an iterable
    or the largest of two or more arguments.

        >>> minmax([3, 1, 5])
        (1, 5)

        >>> minmax(4, 2, 6)
        (2, 6)

    If a *key* function is provided, it will be used to transform the input
    items for comparison.

        >>> minmax([5, 30], key=str)  # '30' sorts before '5'
        (30, 5)

    If a *default* value is provided, it will be returned if there are no
    input items.

        >>> minmax([], default=(0, 0))
        (0, 0)

    Otherwise ``ValueError`` is raised.

    This function is based on the
    `recipe <http://code.activestate.com/recipes/577916/>`__ by
    Raymond Hettinger and takes care to minimize the number of comparisons
    performed.
    """
    iterable = (iterable_or_value, *others) if others else iterable_or_value

    it = iter(iterable)

    try:
        lo = hi = next(it)
    except StopIteration as e:
        if default is _marker:
            raise ValueError(
                '`minmax()` argument is an empty iterable. '
                'Provide a `default` value to suppress this error.'
            ) from e
        return default

    # Different branches depending on the presence of key. This saves a lot
    # of unimportant copies which would slow the "key=None" branch
    # significantly down.
    if key is None:
        for x, y in zip_longest(it, it, fillvalue=lo):
            if y < x:
                x, y = y, x
            if x < lo:
                lo = x
            if hi < y:
                hi = y

    else:
        lo_key = hi_key = key(lo)

        for x, y in zip_longest(it, it, fillvalue=lo):

            x_key, y_key = key(x), key(y)

            if y_key < x_key:
                x, y, x_key, y_key = y, x, y_key, x_key
            if x_key < lo_key:
                lo, lo_key = x, x_key
            if hi_key < y_key:
                hi, hi_key = y, y_key

    return lo, hi


def constrained_batches(
    iterable, max_size, max_count=None, get_len=len, strict=True
):
    """Yield batches of items from *iterable* with a combined size limited by
    *max_size*.

    >>> iterable = [b'12345', b'123', b'12345678', b'1', b'1', b'12', b'1']
    >>> list(constrained_batches(iterable, 10))
    [(b'12345', b'123'), (b'12345678', b'1', b'1'), (b'12', b'1')]

    If a *max_count* is supplied, the number of items per batch is also
    limited:

    >>> iterable = [b'12345', b'123', b'12345678', b'1', b'1', b'12', b'1']
    >>> list(constrained_batches(iterable, 10, max_count = 2))
    [(b'12345', b'123'), (b'12345678', b'1'), (b'1', b'12'), (b'1',)]

    If a *get_len* function is supplied, use that instead of :func:`len` to
    determine item size.

    If *strict* is ``True``, raise ``ValueError`` if any single item is bigger
    than *max_size*. Otherwise, allow single items to exceed *max_size*.
    """
    if max_size <= 0:
        raise ValueError('maximum size must be greater than zero')

    batch = []
    batch_size = 0
    batch_count = 0
    for item in iterable:
        item_len = get_len(item)
        if strict and item_len > max_size:
            raise ValueError('item size exceeds maximum size')

        reached_count = batch_count == max_count
        reached_size = item_len + batch_size > max_size
        if batch_count and (reached_size or reached_count):
            yield tuple(batch)
            batch.clear()
            batch_size = 0
            batch_count = 0

        batch.append(item)
        batch_size += item_len
        batch_count += 1

    if batch:
        yield tuple(batch)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                

    hQ                    8   d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddl
Z
ddlZddlZddlZddlZddlmZmZmZ ddlmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z( ddl)m*Z*m+Z+ 	 ddl,Z,dZ-n
# e.$ r dZ-Y nw xY wg dZ/d	e
j0        dd
         z  Z1da2dej3        fddddddZ4d
 Z5g Z6dfdZ7d Z8 e
j9        de
j:                  Z;d Z< G d d          Z= G d d          Z>d Z? G d d          Z@ G d de@          ZA G d de@          ZB G d de@          ZCd ZD G d  d!e@          ZE G d" d#          ZF G d$ d%eF          ZG G d& d'eG          ZH G d( d)          ZI G d* d+eIe@          ZJ G d, d-eIe@          ZKejL        ZM G d. d/          ZN G d0 d1e@eN          ZO G d2 d3e@eN          ZP G d4 d5e@          ZQ G d6 d7eQ          ZR eSejT        d8          r# G d9 d:eQ          ZUe/V                    d:            G d; d<e@          ZW G d= d>e@          ZXd? ZYd@ ZZ G dA dBe@          Z[dC Z\ G dD dEe@          Z] G dF dGe]          Z^ G dH dIe@          Z_dJZ`eja        dKk    r	ddLlbmcZcmdZd ndM ZcdN Zdi Ze G dO dP          Zf G dQ dRef          ZgdahdS ZidajdT ZkdaldU ZmdandV Zo G dW dX          ZpdY ZqdgdZZrd[ Zse
jt        d\k    rdd]lumvZvmwZw d^ Zxd_ Zyd` Zzda Z{dS eja        dKk    rdb Z|dc Z{dd Z}de ZzdS eqZ{erZzdS )ha
  An extensible library for opening URLs using a variety of protocols

The simplest way to use this module is to call the urlopen function,
which accepts a string containing a URL or a Request object (described
below).  It opens the URL and returns the results as file-like
object; the returned object has some extra methods described below.

The OpenerDirector manages a collection of Handler objects that do
all the actual work.  Each Handler implements a particular protocol or
option.  The OpenerDirector is a composite object that invokes the
Handlers needed to open the requested URL.  For example, the
HTTPHandler performs HTTP GET and POST requests and deals with
non-error returns.  The HTTPRedirectHandler automatically deals with
HTTP 301, 302, 303, 307, and 308 redirect errors, and the
HTTPDigestAuthHandler deals with digest authentication.

urlopen(url, data=None) -- Basic usage is the same as original
urllib.  pass the url and optionally data to post to an HTTP URL, and
get a file-like object back.  One difference is that you can also pass
a Request instance instead of URL.  Raises a URLError (subclass of
OSError); for HTTP errors, raises an HTTPError, which can also be
treated as a valid response.

build_opener -- Function that creates a new OpenerDirector instance.
Will install the default handlers.  Accepts one or more Handlers as
arguments, either instances or Handler classes that it will
instantiate.  If one of the argument is a subclass of the default
handler, the argument will be installed instead of the default.

install_opener -- Installs a new opener as the default opener.

objects of interest:

OpenerDirector -- Sets up the User Agent as the Python-urllib client and manages
the Handler classes, while dealing with requests and responses.

Request -- An object that encapsulates the state of a request.  The
state can be as simple as the URL.  It can also include extra HTTP
headers, e.g. a User-Agent.

BaseHandler --

internals:
BaseHandler and parent
_call_chain conventions

Example usage:

import urllib.request

# set up authentication info
authinfo = urllib.request.HTTPBasicAuthHandler()
authinfo.add_password(realm='PDQ Application',
                      uri='https://mahler:8092/site-updates.py',
                      user='klem',
                      passwd='geheim$parole')

proxy_support = urllib.request.ProxyHandler({"http" : "http://ahad-haam:3128"})

# build a new opener that adds authentication and caching FTP handlers
opener = urllib.request.build_opener(proxy_support, authinfo,
                                     urllib.request.CacheFTPHandler)

# install it
urllib.request.install_opener(opener)

f = urllib.request.urlopen('https://www.python.org/')
    N)URLError	HTTPErrorContentTooShortError)urlparseurlspliturljoinunwrapquoteunquote
_splittype
_splithost
_splitport
_splituser_splitpasswd
_splitattr_splitquery_splitvalue	_splittag	_to_bytesunquote_to_bytes
urlunparse)
addinfourladdclosehookTF)!RequestOpenerDirectorBaseHandlerHTTPDefaultErrorHandlerHTTPRedirectHandlerHTTPCookieProcessorProxyHandlerHTTPPasswordMgrHTTPPasswordMgrWithDefaultRealmHTTPPasswordMgrWithPriorAuthAbstractBasicAuthHandlerHTTPBasicAuthHandlerProxyBasicAuthHandlerAbstractDigestAuthHandlerHTTPDigestAuthHandlerProxyDigestAuthHandlerHTTPHandlerFileHandler
FTPHandlerCacheFTPHandlerDataHandlerUnknownHandlerHTTPErrorProcessorurlopeninstall_openerbuild_openerpathname2urlurl2pathname
getproxiesurlretrieve
urlcleanup	URLopenerFancyURLopenerz%d.%d   )cafilecapath	cadefaultcontextc                   |s|s|rddl } |j        dt          d           |t          d          t          st          d          t          j        t
          j        j        ||          }|	                    dg           t          |	          }t          |          }	nA|r t          |	          }t          |          }	nt          t                      xa}	nt          }	|	
                    | ||          S )
a  Open the URL url, which can be either a string or a Request object.

    *data* must be an object specifying additional data to be sent to
    the server, or None if no such data is needed.  See Request for
    details.

    urllib.request module uses HTTP/1.1 and includes a "Connection:close"
    header in its HTTP requests.

    The optional *timeout* parameter specifies a timeout in seconds for
    blocking operations like the connection attempt (if not specified, the
    global default timeout setting will be used). This only works for HTTP,
    HTTPS and FTP connections.

    If *context* is specified, it must be a ssl.SSLContext instance describing
    the various SSL options. See HTTPSConnection for more details.

    The optional *cafile* and *capath* parameters specify a set of trusted CA
    certificates for HTTPS requests. cafile should point to a single file
    containing a bundle of CA certificates, whereas capath should point to a
    directory of hashed certificate files. More information can be found in
    ssl.SSLContext.load_verify_locations().

    The *cadefault* parameter is ignored.


    This function always returns an object which can work as a
    context manager and has the properties url, headers, and status.
    See urllib.response.addinfourl for more detail on these properties.

    For HTTP and HTTPS URLs, this function returns a http.client.HTTPResponse
    object slightly modified. In addition to the three new methods above, the
    msg attribute contains the same information as the reason attribute ---
    the reason phrase returned by the server --- instead of the response
    headers as it is specified in the documentation for HTTPResponse.

    For FTP, file, and data URLs and requests explicitly handled by legacy
    URLopener and FancyURLopener classes, this function returns a
    urllib.response.addinfourl object.

    Note that None may be returned if no handler handles the request (though
    the default installed global OpenerDirector uses UnknownHandler to ensure
    this never happens).

    In addition, if proxy settings are detected (for example, when a *_proxy
    environment variable like http_proxy is set), ProxyHandler is default
    installed and makes sure the requests are handled through the proxy.

    r   NzJcafile, capath and cadefault are deprecated, use a custom context instead.r;   zDYou can't pass both context and any of cafile, capath, and cadefaultzSSL support not available)r<   r=   zhttp/1.1)r?   )warningswarnDeprecationWarning
ValueError	_have_sslsslcreate_default_contextPurposeSERVER_AUTHset_alpn_protocolsHTTPSHandlerr3   _openeropen)
urldatatimeoutr<   r=   r>   r?   rA   
https_handleropeners
             %/usr/lib/python3.11/urllib/request.pyr1   r1      s/   h   9 
 01CQ	H 	H 	H  
  	:8999,S[-D4:4:< < < 	""J<000$W555
m,,	 $W555
m,,	'>>)&&;;sD'***    c                 
    | a d S N)rL   )rR   s    rS   r2   r2      s    GGGrT   c                 L   t          |           \  }}t          j        t          | |                    5 }|                                }|dk    r/|s-t
          j                            |          |fcddd           S |rt          |d          }n6t          j
        d          }|j        }t          
                    |           |5  ||f}	d}
d}d}d}
d	|v rt          |d
                   }|r
 ||
|
|           	 |                    |
          }|sn<|t!          |          z
  }|                    |           |
dz
  }
|r
 ||
|
|           T	 ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   |dk    r||k     rt%          d
||fz  |	          |	S )aW  
    Retrieve a URL into a temporary location on disk.

    Requires a URL argument. If a filename is passed, it is used as
    the temporary file location. The reporthook argument should be
    a callable that accepts a block number, a read size, and the
    total file size of the URL target. The data argument should be
    valid URL encoded data.

    If a filename is passed and the URL points to a local resource,
    the result is a copy from local file to new file.

    Returns a tuple containing the path to the newly created
    data file as well as the resulting HTTPMessage object.
    fileNwbF)delete    r   content-lengthContent-LengthT   1retrieval incomplete: got only %i out of %i bytes)r   
contextlibclosingr1   infoospathnormpathrM   tempfileNamedTemporaryFilename_url_tempfilesappendintreadlenwriter   )rN   filename
reporthookrO   url_typere   fpheaderstfpresultbssizerm   blocknumblocks                  rS   r7   r7      s      __NHd		GC..	/	/ $32'')) vh7##D))72
$3 $3 $3 $3 $3 $3 $3 $3  	,x&&CC-U;;;CxH!!(+++
 	3 	3w&FBDDH7**7#3455 
/
8R...
3 E

"		%   A
 3JxT222
3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3!$3 $3 $3 $3 $3 $3 $3 $3 $3 $3 $3 $3 $3 $3 $3L qyyTD[["?Tl
"$ $ 	$ Ms=   =E8?AE8
B
E!E8!E%	%E8(E%	)E88E<?E<c                      t           D ]'} 	 t          j        |            # t          $ r Y $w xY wt           dd= t          rdadS dS )z0Clean up temporary files from urlretrieve calls.N)rj   rd   unlinkOSErrorrL   )	temp_files    rS   r8   r8     sr    #  		Ii     	 	 	D	 	qqq  s    
--z:\d+$c                     | j         }t          |          d         }|dk    r|                     dd          }t                              d|d          }|                                S )zReturn request-host, as defined by RFC 2965.

    Variation from RFC: returned value is lowercased, for convenient
    comparison.

    r_    Host)full_urlr   
get_header_cut_port_resublower)requestrN   hosts      rS   request_hostr   -  sa     
CC==Drzz!!&"-- Ba((D::<<rT   c                      e Zd Zdi dddfdZed             Zej        d             Zej        d             Zed             Zej        d             Zej        d	             Zd
 Z	d Z
d Zd
 Zd Z
d Zd Zd ZddZd Zd ZdS )r   NFc                    || _         i | _        i | _        d | _        || _        d | _        |                                D ]\  }}|                     ||           |t          |           }|| _	        || _
        |r	|| _        d S d S rV   )r   rt   unredirected_hdrs_datarO   _tunnel_hostitems
add_headerr   origin_req_hostunverifiablemethod)	selfrN   rO   rt   r   r   r   keyvalues	            rS   __init__zRequest.__init__?  s     
!#
	 !--// 	( 	(JCOOC''''"*400O.( 	! DKKK	! 	!rT   c                 ^    | j         r d                    | j        | j                   S | j        S )Nz{}#{})fragmentformat	_full_urlr   s    rS   r   zRequest.full_urlQ  s-    = 	A>>$.$-@@@~rT   c                     t          |          | _        t          | j                  \  | _        | _        |                                  d S rV   )r	   r   r   r   _parser   rN   s     rS   r   zRequest.full_urlW  s:      (1$.(A(A%





rT   c                 0    d | _         d | _        d| _        d S )Nr   )r   r   selectorr   s    rS   r   zRequest.full_url^  s    



rT   c                     | j         S rV   )r   r   s    rS   rO   zRequest.datad  s
    zrT   c                     || j         k    r3|| _         |                     d          r|                     d           d S d S d S )NContent-length)r   
has_header
remove_header)r   rO   s     rS   rO   zRequest.datah  sZ    4:DJ /00 
5""#344444
 

5 
5rT   c                     d | _         d S rV   )rO   r   s    rS   rO   zRequest.datar  s
    			rT   c                     t          | j                  \  | _        }| j        t          d| j        z            t          |          \  | _        | _        | j        rt          | j                  | _        d S d S )Nzunknown url type: %r)	r   r   typerD   r   r
   r   r   r   )r   rests     rS   r   zRequest._parsev  st    $T^44	493dmCDDD#-d#3#3 	4=9 	+	**DIII	+ 	+rT   c                 :    | j         dnd}t          | d|          S )z3Return a string indicating the HTTP request method.NPOSTGETr   )rO   getattr)r   default_methods     rS   
get_methodzRequest.get_method~  s$    #'9#8etX~666rT   c                     | j         S rV   )r   r   s    rS   get_full_urlzRequest.get_full_url  s
    }rT   c                 x    | j         dk    r| j        s
| j        | _        n|| _         | j        | _        || _        d S )Nhttps)r   r   r   r   r   )r   r   r   s      rS   	set_proxyzRequest.set_proxy  s?    9(9 $	DDI MDM			rT   c                 "    | j         | j        k    S rV   )r   r   r   s    rS   	has_proxyzRequest.has_proxy  s    }
--rT   c                 >    || j         |                                <   d S rV   )rt   
capitalizer   r   vals      rS   r   zRequest.add_header  s    ),S^^%%&&&rT   c                 >    || j         |                                <   d S rV   )r   r   r   s      rS   add_unredirected_headerzRequest.add_unredirected_header  s    36s~~//000rT   c                 &    || j         v p|| j        v S rV   )rt   r   r   header_names     rS   r   zRequest.has_header  s!    t|+ 6t55	7rT   c                 j    | j                             || j                            ||                    S rV   )rt   getr   )r   r   defaults      rS   r   zRequest.get_header  s5    |"&&{G<<> > 	>rT   c                 r    | j                             |d            | j                            |d            d S rV   )rt   popr   r   s     rS   r   zRequest.remove_header  s9    d+++"";55555rT   c                 d    i | j         | j        }t          |                                          S rV   )r   rt   listr   )r   hdrss     rS   header_itemszRequest.header_items  s,    9$(9DL9DJJLL!!!rT   rV   )__name__
__module____qualname__r   propertyr   setterdeleterrO   r   r   r   r   r   r   r   r   r   r   r    rT   rS   r   r   =  s       !%r!%E! ! ! !$   X
 _  _   
   X 
[5 5 [5 
\  \+ + +7 7 7
    . . .- - -7 7 77 7 7> > > >
6 6 6" " " " "rT   r   c                   J    e Zd Zd Zd Zd Zd Zdej        fdZ	d	dZ
d ZdS )
r   c                 t    dt           z  }d|fg| _        g | _        i | _        i | _        i | _        i | _        d S )NPython-urllib/%sz
User-agent)__version__
addheadershandlershandle_openhandle_errorprocess_responseprocess_request)r   client_versions     rS   r   zOpenerDirector.__init__  sH    +k9(.9:
 "!rT   c                 L   t          |d          st          dt          |          z            d}t          |          D ].}|dv r|                    d          }|d |         }||dz   d          }|                    d          ro|                    d          |z   dz   }||dz   d          }	 t
          |          }n# t          $ r Y nw xY w| j        	                    |i           }	|	| j        |<   n1|dk    r
|}| j
        }	n!|d	k    r
|}| j        }	n|d
k    r
|}| j        }	n|	
                    |g           }
|
rt          j        |
|           n|
                    |           d}0|r1t          j        | j        |           |                    |            d S d S )N
add_parentz%expected BaseHandler instance, got %rF)redirect_requestdo_open
proxy_open_r_   errorrM   responser   T)hasattr	TypeErrorr   dirfind
startswithrl   rD   r   r   r   r   r   
setdefaultbisectinsortrk   r   r   )r   handleraddedmethiprotocol	conditionjkindlookupr   s              rS   add_handlerzOpenerDirector.add_handler  s   w-- 	+C MM* + + 
+ LL #	 #	DDDD		#ABQBxHQqSTT
I##G,, 
NN3''!+a/AaCDDzt99DD!   D*..x<<.4!(++f$$)j((.i''-((r22H 
)
h0000(((EE 	%M$-111t$$$$$	% 	%s   3C
CCc                     d S rV   r   r   s    rS   closezOpenerDirector.close      rT   c                 r    |                     |d          }|D ]}t          ||          } || }||c S d S )Nr   )r   r   )	r   chainr   	meth_nameargsr   r   funcrv   s	            rS   _call_chainzOpenerDirector._call_chain  s^     99T2&& 	 	G7I..DT4[F!


 "	 	rT   Nc                    t          |t                    rt          ||          }n|}|||_        ||_        |j        }|dz   }| j                            |g           D ]}t          ||          } ||          }t          j
        d|j        |j        |j        |
                                           |                     ||          }	|dz   }| j                            |g           D ]}t          ||          } |||	          }	|	S )N_requestzurllib.Request	_response)
isinstancestrr   rO   rP   r   r   r   r   sysauditr   rt   r   _openr   )
r   fullurlrO   rP   reqr   r   	processorr   r   s
             rS   rM   zOpenerDirector.open  s"   gs## 	 '4((CCC8 Z'	-11(B?? 	 	I9i00D$s))CC	"CL#(CKIYIYZZZ::c4(( [(	.228R@@ 	+ 	+I9i00DtC**HHrT   c                     |                      | j        dd|          }|r|S |j        }|                      | j        ||dz   |          }|r|S |                      | j        dd|          S )Nr   default_openr  unknownunknown_open)r   r   r   )r   r  rO   rv   r   s        rS   r  zOpenerDirector._open  s    !!$"2I"0#7 7 	M8!!$"2Hh")?*+.0 0 	M 0) .5 5 	5rT   c                     |dv r| j         d         }|d         }d|z  }d}|}n| j         }|dz   }d}|||f|z   } | j        | }|r|S |r|dd	f|z   } | j        | S d S )
Nhttpr   r  r;   z
http_error_%sr_   _errorr   r   http_error_default)r   r   )r   protor   dictr   http_err	orig_argsrv   s           rS   r   zOpenerDirector.error   s    %%%$V,DGE'%/IHII$D(IHeY'$.!!4( 	M 	+)%9:YFD#4#T**	+ 	+rT   rV   )r   r   r   r   r   r   r   socket_GLOBAL_DEFAULT_TIMEOUTrM   r  r   r   rT   rS   r   r     s        	" 	" 	"-% -% -%^
 
 
	 	 	 "&v/M    :
5 
5 
5 
5+ + + + +rT   r   c            	         t                      }t          t          t          t          t
          t          t          t          t          g	}t          t          j        d          r|
                    t                     t                      }|D ]g}| D ]b}t!          |t"                    r&t%          ||          r|                    |           =t!          ||          r|                    |           ch|D ]}|                    |           |D ]}|                     |                        | D ]6}t!          |t"                    r
 |            }|                    |           7|S )a*  Create an opener object from a list of handlers.

    The opener will use several default handlers, including support
    for HTTP, FTP and when applicable HTTPS.

    If any of the handlers passed as arguments are subclasses of the
    default handlers, the default handlers will not be used.
    HTTPSConnection)r   r    r/   r*   r   r   r,   r+   r0   r.   r   r  clientrk   rK   setr  r   
issubclassaddremover   )r   rR   default_classesskipklasscheckhs          rS   r3   r3   9  sw    

F#^[.0C!;0B"$O t{-.. -|,,,55D      	  	 E%&& 
 eU++ $HHUOOOE5)) 
 	   & &u%%%%  $ $5577####
  a 	A1MrT   c                   $    e Zd ZdZd Zd Zd ZdS )r     c                     || _         d S rV   )parent)r   r(  s     rS   r   zBaseHandler.add_parent`  s
    rT   c                     d S rV   r   r   s    rS   r   zBaseHandler.closec  r   rT   c                 F    t          |d          sdS | j        |j        k     S )N
handler_orderT)r   r+  )r   others     rS   __lt__zBaseHandler.__lt__g  s,    uo.. 	 4!E$777rT   N)r   r   r   r+  r   r   r-  r   rT   rS   r   r   ]  sF        M  
 
 
8 8 8 8 8rT   r   c                        e Zd ZdZdZd ZeZdS )r0   zProcess HTTP error responses.i  c                     |j         |j        |                                }}}d|cxk    rdk     s!n | j                            d|||||          }|S )N   ,  r  )codemsgrc   r(  r   )r   r   r   r2  r3  r   s         rS   
http_responsez HTTPErrorProcessor.http_responset  sg    "-x}}4c t!!!!c!!!!{((4d< <H rT   N)r   r   r   __doc__r+  r4  https_responser   rT   rS   r0   r0   p  s/        ''M	 	 	 #NNNrT   r0   c                       e Zd Zd ZdS )r   c                 2    t          |j        ||||          rV   )r   r   )r   r  rs   r2  r3  r   s         rS   r  z*HTTPDefaultErrorHandler.http_error_default  s    dCr:::rT   N)r   r   r   r  r   rT   rS   r   r     s#        ; ; ; ; ;rT   r   c                   6    e Zd ZdZdZd Zd ZexZxZxZ	Z
dZdS )r      
   c                 *  	 |                                 }|dv r|dv s"|dv r|dk    st          |j        ||||          |                    dd          }d		fd|j                                        D             }t
          |||j        d	
          S )a  Return a Request or None in response to a redirect.

        This is called by the http_error_30x methods when a
        redirection response is received.  If a redirection should
        take place, return a new Request to allow http_error_30x to
        perform the redirect.  Otherwise, raise HTTPError if no-one
        else should try to handle this url.  Return None if you can't
        but another Handler might.
        )-  .  /  i3  i4  )r   HEAD)r=  r>  r?  r    z%20)r]   zcontent-typec                 H    i | ]\  }}|                                 v||S r   )r   ).0kvCONTENT_HEADERSs      rS   
<dictcomp>z8HTTPRedirectHandler.redirect_request.<locals>.<dictcomp>  s;     ; ; ;tq!/99 999rT   T)rt   r   r   )r   r   r   replacert   r   r   r   )
r   r  rs   r2  r3  rt   newurlm
newheadersrF  s
            @rS   r   z$HTTPRedirectHandler.redirect_request  s     
NN222qO7K7K&&1;;CL$WbAAA U++<; ; ; ;s{'8'8':': ; ; ;
v)'*':$(* * * 	*rT   c                 r   d|v r	|d         }nd|v r	|d         }nd S t          |          }|j        dvrt          |||d|d||          |j        s|j        rt          |          }d|d<   t
          |          }t          |dt          j	        	          }t          |j        |          }|                     ||||||          }|d S t          |d
          rf|j        x}	|_        |	                    |d          | j        k    st#          |	          | j        k    r t          |j        || j        |z   ||          ni x}	x|_        |_        |	                    |d          dz   |	|<   |                                 |                                 | j                            ||j        
          S )Nlocationurir  r   ftpr   z - Redirection to url 'z' is not allowed/r;   z
iso-8859-1)encodingsafe
redirect_dictr   r_   rP   )r   schemer   re   netlocr   r   r
   stringpunctuationr   r   r   r   rT  r   max_repeatsrn   max_redirectionsinf_msgrm   r   r(  rM   rP   )
r   r  rs   r2  r3  rt   rI  urlpartsnewvisiteds
             rS   http_error_302z"HTTPRedirectHandler.http_error_302  s      Z(FF
g

U^FFF F##
 ?">>>ADfffM  

 } 	 	H~~HHQKH%%
 \0BD D Dv..
 ##CT3HH;F 3(( 	A*-*;;Gc'FA&&$*:::G 555d $s 2GRA A A 6 ?A@G@c'#*;!++fa0014 				



{S[999rT   zoThe HTTP server returned a redirect error that would lead to an infinite loop.
The last 30x error message was:
N)r   r   r   rZ  r[  r   r`  http_error_301http_error_303http_error_307http_error_308r\  r   rT   rS   r   r     s\         K  *  *  *L:: :: ::x IWVNV^Vn~2GGGrT   r   c                    t          |           \  }}|                    d          sd}| }n|                    d          st          d| z            d|v r,|                    d          }|                    d|          }n|                    dd          }|dk    rd}|d|         }t	          |          \  }}|t          |          \  }}	ndx}}	|||	|fS )a  Return (scheme, user, password, host/port) given a URL or an authority.

    If a URL is supplied, it must have an authority (host:port) component.
    According to RFC 3986, having an authority component means the URL must
    have two slashes after the scheme.
    rQ  N//zproxy URL with no authority: %r@r;   r\   )r   r   rD   r   r   r   )
proxyrV  r_scheme	authorityhost_separatorenduserinfohostportuserpasswords
             rS   _parse_proxyrq    s    "%((FHs## $		 ""4(( 	H>FGGG (??%]]3//N--^44CC--Q''C"99CQsUO	#I..Hh%h//hhx48++rT   c                        e Zd ZdZddZd ZdS )r    d   Nc                     |t                      }t          |d          s
J d            || _        |                                D ]7\  }}|                                }t          | d|z  ||| j        fd           8d S )Nkeysproxies must be a mappingz%s_openc                      || ||          S rV   r   )rrh  r   r   s       rS   <lambda>z'ProxyHandler.__init__.<locals>.<lambda>#  s    Qt,, rT   )r6   r   proxiesr   r   setattrr   )r   rz  r   rN   s       rS   r   zProxyHandler.__init__  s    ? llGw''DD)DDDD  	. 	.ID#::<<DD)d*$'d - - -
. 
. 
. 
.	. 	.rT   c                    |j         }t          |          \  }}}}||}|j        rt          |j                  rd S |ru|rst	          |          dt	          |          }	t          j        |	                                                              d          }
|	                    dd|
z              t	          |          }|
                    ||           ||k    s|dk    rd S | j                            ||j
                  S )N:asciiProxy-authorizationBasic r   rU  )r   rq  r   proxy_bypassr   base64	b64encodeencodedecoder   r   r(  rM   rP   )r   r  rh  r   	orig_type
proxy_typero  rp  rn  	user_passcredss              rS   r   zProxyHandler.proxy_open&  s   H	/;E/B/B,
D(H"J8 	SX.. 	4 	DH 	D#*4====#*8#4#4#46I$Y%5%5%7%788??HHENN0(U2BCCC8$$

h
+++
""i7&:&:4 ;##C#===rT   rV   )r   r   r   r+  r   r   r   rT   rS   r    r      s<        M	. 	. 	. 	.> > > > >rT   r    c                   .    e Zd Zd Zd Zd ZddZd ZdS )	r!   c                     i | _         d S rV   )passwdr   s    rS   r   zHTTPPasswordMgr.__init__D  s
    rT   c                      t          |t                    r|g}| j        vr
i  j        |<   dD ]0t           fd|D                       }||f j        |         |<   1d S )NTFc              3   D   K   | ]}                     |          V  d S rV   )
reduce_uri)rC  udefault_portr   s     rS   	<genexpr>z/HTTPPasswordMgr.add_password.<locals>.<genexpr>N  sB        ?  ?56<00 ?  ?  ?  ?  ?  ?rT   )r  r  r  tuple)r   realmrN  ro  r  reduced_urir  s   `     @rS   add_passwordzHTTPPasswordMgr.add_passwordG  s    c3 	%C##!#DK' 	= 	=L  ?  ?  ?  ?  ?:= ?  ?  ? ? ?K/3VnDK{++	= 	=rT   c                     | j                             |i           }dD ]U}|                     ||          }|                                D ](\  }}|D ] }|                     ||          r|c c c S !)VdS )Nr  NN)r  r   r  r   	is_suburi)	r   r  authuridomainsr  reduced_authuriurisauthinforN  s	            rS   find_user_passwordz"HTTPPasswordMgr.find_user_passwordR  s    +//%,,' 	( 	(L"oog|DDO")--// 
( 
(h ( (C~~c?;; ('((
( zrT   Tc                     t          |          }|d         r|d         }|d         }|d         pd}nd}|}d}t          |          \  }}|r%|#|!ddd                    |          }	|	d	||	fz  }||fS )
z@Accept authority or URI and extract only the authority and path.r_   r   r;   rQ  NP   i  r  z%s:%d)r   r   r   )
r   rN  r  partsrV  rj  re   r   portdports
             rS   r  zHTTPPasswordMgr.reduce_uri\  s     

8 		1XFaI8?sDD FID	**
d 	4DLV-?! s6{{ 
  #tUm3	$rT   c                     ||k    rdS |d         |d         k    rdS |d         }|dd         dk    r|dz
  }|d                              |          S )zcCheck if test is below base in a URI tree

        Both args must be URIs in reduced form.
        Tr   Fr_   r\   NrQ  )r   )r   basetestprefixs       rS   r  zHTTPPasswordMgr.is_suburis  sg    
 4<<47d1g5a"##;#cMFAw!!&)))rT   N)T)r   r   r   r   r  r  r  r  r   rT   rS   r!   r!   B  sd          	= 	= 	=     .* * * * *rT   r!   c                       e Zd Zd ZdS )r"   c                     t                               | ||          \  }}|||fS t                               | d |          S rV   )r!   r  )r   r  r  ro  rp  s        rS   r  z2HTTPPasswordMgrWithDefaultRealm.find_user_password  sL    (;;D%<CE Eh>!11$gFFFrT   N)r   r   r   r  r   rT   rS   r"   r"     s(        G G G G GrT   r"   c                   8     e Zd Z fdZd fd	ZddZd Z xZS )r#   c                 H    i | _          t                      j        |i | d S rV   )
authenticatedsuperr   )r   r   kwargs	__class__s      rS   r   z%HTTPPasswordMgrWithPriorAuth.__init__  s-    $)&)))))rT   Fc                     |                      ||           |$t                                          d |||           t                                          ||||           d S rV   )update_authenticatedr  r  )r   r  rN  ro  r  is_authenticatedr  s         rS   r  z)HTTPPasswordMgrWithPriorAuth.add_password  sb    !!#'7888GG  sD&999
UCv66666rT   c                     t          |t                    r|g}dD ]'}|D ]"}|                     ||          }|| j        |<   #(d S Nr  )r  r  r  r  )r   rN  r  r  r  r  s         rS   r  z1HTTPPasswordMgrWithPriorAuth.update_authenticated  sr    c3 	%C' 	C 	CL 
C 
C"ooa>>2B";//
C	C 	CrT   c                     dD ]I}|                      ||          }| j        D ])}|                     ||          r| j        |         c c S *Jd S r  )r  r  r  )r   r  r  r  rN  s        rS   r  z-HTTPPasswordMgrWithPriorAuth.is_authenticated  sz    ' 	3 	3L"oog|DDO) 
3 
3>>#77 3-c2222223
3	3 	3rT   )F)r   r   r   r   r  r  r  
__classcell__)r  s   @rS   r#   r#     s}        * * * * *7 7 7 7 7 7C C C C3 3 3 3 3 3 3rT   r#   c                   h    e Zd Z ej        dej                  Zd	dZd Zd Z	d Z
d Zd ZeZ
eZdS )
r$   z1(?:^|,)[ 	]*([^ 	,]+)[ 	]+realm=(["']?)([^"']*)\2Nc                 V    |t                      }|| _        | j        j        | _        d S rV   )r!   r  r  )r   password_mgrs     rS   r   z!AbstractBasicAuthHandler.__init__  s-    *,,L" K4rT   c              #   "  K   d}t           j                            |          D ]A}|                                \  }}}|dvrt	          j        dt          d           ||fV  d}B|s'|r|                                d         }nd}|d fV  d S d S )NF)"'zBasic Auth Realm was unquoted   Tr   r   )r$   rxfinditergroupsrA   rB   UserWarningsplit)r   headerfound_challengemorV  r
   r  s          rS   _parse_realmz%AbstractBasicAuthHandler._parse_realm  s      *-66v>> 	# 	#B#%99;; FE5J&&
=)1. . . 5/!!!"OO 	! 
*4.     	! 	!rT   c                    |                     |          }|sd S d }|D ]U}|                     |          D ]=\  }}|                                dk    r|} ||                     |||          c c S >V|t	          d|          d S )Nbasicz@AbstractBasicAuthHandler does not support the following scheme: )get_allr  r   retry_http_basic_authrD   )	r   authreqr   r  rt   unsupportedr  rV  r  s	            rS   http_error_auth_reqedz.AbstractBasicAuthHandler.http_error_auth_reqed  s     //'** 	F 
	H 
	HF!%!2!26!:!: 	
H 	
H
<<>>W,,"(K$  55dCGGGGGGG	 %	
H "* &) * * 
* #"rT   c                    | j                             ||          \  }}||d|}dt          j        |                                                              d          z   }|                    | j        d           |k    rd S |                    | j        |           | j	        
                    ||j                  S d S )Nr}  r  r~  rU  )r  r  r  r  r  r  r   auth_headerr   r(  rM   rP   )r   r   r  r  ro  pwrawauths           rS   r  z.AbstractBasicAuthHandler.retry_http_basic_auth  s    ;11%>>b
>!TT22&Cf.szz||<<CCGLLLD~~d.55==t''(8$???;##C#===4rT   c                    t          | j        d          r| j                            |j                  s|S |                    d          s| j                            d |j                  \  }}d                    ||                                          }t          j	        |          
                                }|                    dd                    |                                                     |S )Nr  
Authorizationz{0}:{1}zBasic {})
r   r  r  r   r   r  r   r  r  standard_b64encoder  r   strip)r   r  ro  r  credentialsauth_strs         rS   http_requestz%AbstractBasicAuthHandler.http_request   s    %788 	{++CL99	J~~o.. 	M;99$MMLD&#**488??AAK0==DDFFH''(2(9(9(..:J:J(K(K
M 
M 
M
rT   c                     t          | j        d          rVd|j        cxk    rdk     r$n n!| j                            |j        d           n | j                            |j        d           |S )Nr  r0  r1  TF)r   r  r2  r  r   )r   r  r   s      rS   r4  z&AbstractBasicAuthHandler.http_response
  sx    4; 233 	Fhm))))c)))))00tDDDD00uEEErT   rV   )r   r   r   recompileIr  r   r  r  r  r  r4  
https_requestr6  r   rT   rS   r$   r$     s         
 1 D
 
B5 5 5 5! ! !(* * *4
 
 
     !M"NNNrT   r$   c                       e Zd ZdZd ZdS )r%   r  c                 D    |j         }|                     d|||          }|S )Nwww-authenticate)r   r  )r   r  rs   r2  r3  rt   rN   r   s           rS   http_error_401z#HTTPBasicAuthHandler.http_error_401  s-    l--.@*-sG= =rT   N)r   r   r   r  r  r   rT   rS   r%   r%     s(        !K    rT   r%   c                       e Zd ZdZd ZdS )r&   r  c                 D    |j         }|                     d|||          }|S Nproxy-authenticate)r   r  )r   r  rs   r2  r3  rt   rj  r   s           rS   http_error_407z$ProxyBasicAuthHandler.http_error_407)  s1    
 H	--.B*3S'C CrT   N)r   r   r   r  r  r   rT   rS   r&   r&   %  s(        'K    rT   r&   c                   @    e Zd Zd
dZd Zd Zd Zd Zd Zd Z	d	 Z
dS )r'   Nc                     |t                      }|| _        | j        j        | _        d| _        d| _        d | _        d S Nr   )r!   r  r  retriednonce_count
last_nonce)r   r  s     rS   r   z"AbstractDigestAuthHandler.__init__C  s@    >$&&F K4rT   c                     d| _         d S r  )r  r   s    rS   reset_retry_countz+AbstractDigestAuthHandler.reset_retry_countL  s
    rT   c                    |                     |d           }| j        dk    rt          |j        dd|d           | xj        dz
  c_        |rr|                                d         }|                                dk    r|                     ||          S |                                dk    rt          d|z            d S d S )	N   i  zdigest auth failedr_   r   digestr  zEAbstractDigestAuthHandler does not support the following scheme: '%s')r   r  r   r   r  r   retry_http_digest_authrD   )r   r  r   r  rt   r  rV  s          rS   r  z/AbstractDigestAuthHandler.http_error_auth_reqedO  s    ++k400<! CL#/C#T+ + 
+ 
LLALL 	I]]__Q'F||~~))223@@@7**  "?AG"H I I I	I 	I +*rT   c                    |                     dd          \  }}t          t          d t          |                              }|                     ||          }|rid|z  }|j                            | j        d           |k    rd S |                    | j        |           | j	        
                    ||j                  }|S d S )NrA  r_   z	Digest %srU  )r  parse_keqv_listfilterparse_http_listget_authorizationrt   r   r  r   r(  rM   rP   )r   r  r  token	challengechalauth_valresps           rS   r  z0AbstractDigestAuthHandler.retry_http_digest_authc  s    ::c1--yvdOI,F,FGGHH%%c400 	"T)H{t/66(BBt''(8(CCC;##C#==DK
	 	rT   c                     | j         d|dt          j                    d}|                    d          t	          d          z   }t          j        |                                          }|d d         S )Nr}  r~        )r  timectimer  _randombyteshashlibsha1	hexdigest)r   noncesbdigs        rS   
get_cnoncez$AbstractDigestAuthHandler.get_cnonceo  si      +++UUUDJLLLLA
HHWQ/l1oo''))3B3xrT   c                    	 |d         }|d         }|                     d          }|                     dd          }|                     dd           }n# t          $ r Y d S w xY w|                     |          \  }}	|d S | j                            ||j                  \  }
}|
d S |j        |                     |j        |          }nd }|
d|d|}
|                                d|j	        }|$ |	 ||
          |d ||                    }nd|
                    d	          v rx|| j        k    r| xj        d
z
  c_        nd
| _        || _        d| j        z  }| 
                    |          }|d|d|ddd ||          	} |	 ||
          |          }nt          d|z            d
|
d|d|d|j	        d|d}|r|d|z  z
  }|r|d|z  z
  }|d|z  z
  }|r|d|d|dz
  }|S )Nr  r	  qop	algorithmMD5opaquer}  r  ,r_   z%08xzqop '%s' is not supported.z
username="z
", realm="z
", nonce="z", uri="z
", response="r  z
, opaque="%s"z
, digest="%s"z, algorithm="%s"z, qop=auth, nc=z
, cnonce=")r   KeyErrorget_algorithm_implsr  r  r   rO   get_entity_digestr   r   r  r  r  r
  r   )r   r  r  r  r	  r  r  r  HKDro  r  entdigA1A2respdigncvaluecnoncenoncebitr  s                       rS   r  z+AbstractDigestAuthHandler.get_authorizationz  s   		MEME((5//Ce44I XXh--FF 	 	 	44	 ((33294;11%FFb<4 8++CHd;;FFF44
+((((&
 ;b2555!!B%%% 899GG
syy~~
%
%''  A%   #$ "'t//G__U++F+055'''66666611R555QHb2))GG 7#=>>>
 #'$$uuuclll")''+  	-Of,,D 	-Of,,D"Y.. 	IDHHDs   AA 
A"!A"c                 b    |dk    rd n|dk    rd nt          d|z            fd}|fS )Nr  c                 t    t          j        |                     d                                                    S Nr~  )r  md5r  r  xs    rS   ry  z?AbstractDigestAuthHandler.get_algorithm_impls.<locals>.<lambda>  s(    '+ahhw&7&788BBDD rT   SHAc                 t    t          j        |                     d                                                    S r"  )r  r  r  r  r$  s    rS   ry  z?AbstractDigestAuthHandler.get_algorithm_impls.<locals>.<lambda>  s(    ',qxx'8'899CCEE rT   z.Unsupported digest authentication algorithm %rc                 $     | d|          S )Nr}  r   )r
  dr  s     rS   ry  z?AbstractDigestAuthHandler.get_algorithm_impls.<locals>.<lambda>  s    !!qqq!!,-- rT   )rD   )r   r  r  r  s      @rS   r  z-AbstractDigestAuthHandler.get_algorithm_impls  se    DDAA
%

EEAA  ,.78 9 9 
9
-
-
-
-"urT   c                     d S rV   r   )r   rO   r  s      rS   r  z+AbstractDigestAuthHandler.get_entity_digest  s    trT   rV   )r   r   r   r   r  r  r  r
  r  r  r  r   rT   rS   r'   r'   8  s             I I I(
 
 
	 	 	< < <|      rT   r'   c                        e Zd ZdZdZdZd ZdS )r(   zAn authentication protocol defined by RFC 2069

    Digest authentication improves on basic authentication because it
    does not transmit passwords in the clear.
    r    c                     t          |j                  d         }|                     d|||          }|                                  |S )Nr_   r  )r   r   r  r  r   r  rs   r2  r3  rt   r   retrys           rS   r  z$HTTPDigestAuthHandler.http_error_401  sL    %%a(**+=+/g? ?   rT   N)r   r   r   r5  r  r+  r  r   rT   rS   r(   r(     s9          "KM    rT   r(   c                       e Zd ZdZdZd ZdS )r)   Proxy-Authorizationr,  c                 l    |j         }|                     d|||          }|                                  |S r  )r   r  r  r.  s           rS   r  z%ProxyDigestAuthHandler.http_error_407  s?    x**+?+/g? ?   rT   N)r   r   r   r  r+  r  r   rT   rS   r)   r)     s-        'KM    rT   r)   c                   .    e Zd ZddZd Zd Zd Zd ZdS )	AbstractHTTPHandlerr   c                     || _         d S rV   _debuglevel)r   
debuglevels     rS   r   zAbstractHTTPHandler.__init__  s    %rT   c                     || _         d S rV   r6  )r   levels     rS   set_http_debuglevelz'AbstractHTTPHandler.set_http_debuglevel  s     rT   c                 z    t           j        j                            |j        |                                          S rV   )r  r  HTTPConnection_get_content_lengthrO   r   r   r   s     rS   r>  z'AbstractHTTPHandler._get_content_length  s3    {)==L  " " 	"rT   c                 `   |j         }|st          d          |j        |j        }t          |t                    rd}t          |          |                    d          s|                    dd           |                    d          sf|                    d          sQ|                     |          }|$|                    dt	          |                     n|                    dd           |}|	                                r)t          |j                  \  }}t          |          \  }}	|                    d          s|                    d|           | j
        j        D ]D\  }
}|
                                }
|                    |
          s|                    |
|           E|S )	N
no host givenz\POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.zContent-type!application/x-www-form-urlencodedr   Transfer-encodingchunkedr   )r   r   rO   r  r  r   r   r   r>  r   r   r   r
   r(  r   r   )r   r   r   rO   r3  content_lengthsel_hostrV  selsel_pathri   r   s               rS   do_request_zAbstractHTTPHandler.do_request_  s   | 	,?+++<#<D$$$ 
%Dnn$%%n55 
9//"79 9 9 &&'788 
<#../BCC
<!%!9!9'!B!B!-33,c..A.AC C C C 33/< < <  	1$W%566KFC!+CHh!!&)) 	>++FH===;1 	= 	=KD%??$$D%%d++ 
=//e<<<rT   c           	        
 |j         }|st          d           ||fd|j        i|}|                    | j                   t          |j                  

                    
fd|j        	                                D                        d
d<   d 
	                                D             
|j
        r2i }d}|
v r
|         ||<   
|= |                    |j
        |           	 	 |                    |
                                |j        |j        
|                    d	          
           n!# t"          $ r}t          |          d}~ww xY w|                                }	n#  |                                  xY w|j        r |j                                         d|_        |                                |	_        |	j        |	_        |	S )zReturn an HTTPResponse object for the request, using http_class.

        http_class must implement the HTTPConnection API from http.client.
        rA  rP   c                 $    i | ]\  }}|v	||
S r   r   )rC  rD  rE  rt   s      rS   rG  z/AbstractHTTPHandler.do_open.<locals>.<dictcomp>)  s3     - - -AG++ 1+++rT   r   
Connectionc                 >    i | ]\  }}|                                 |S r   )title)rC  ri   r   s      rS   rG  z/AbstractHTTPHandler.do_open.<locals>.<dictcomp>6  s&    FFFs4::<<FFFrT   r1  rt   rC  )encode_chunkedN)r   r   rP   set_debuglevelr7  r  r   updatert   r   r   
set_tunnelr   r   r   rO   r   r}   getresponser   sockr   rN   reasonr3  )r   
http_classr  http_conn_argsr   r$  tunnel_headersproxy_auth_hdrerrrx  rt   s             @rS   r   zAbstractHTTPHandler.do_open  s   
 x 	,?+++ 
JtCCS[CNCC	)***s,-- - - - -):):)<)< - - - 	. 	. 	. !(FFgmmooFFF 	CN2N((181H~. N+
LL)>LBBB		
$		#..**CL#(G),8K)L)L  N N N N 
$ 
$ 
$smm#
$

AA	
GGIII
 
6 	
FLLNNNAF  "" s+   .A	D8 7E. 8
EEEE. .FNr   )r   r   r   r   r;  r>  rI  r   r   rT   rS   r4  r4    sj        & & & &! ! !" " "
$ $ $L@ @ @ @ @rT   r4  c                   "    e Zd Zd Zej        ZdS )r*   c                 L    |                      t          j        j        |          S rV   )r   r  r  r=  r   r  s     rS   	http_openzHTTPHandler.http_open`  s    ||DK6<<<rT   N)r   r   r   r`  r4  rI  r  r   rT   rS   r*   r*   ^  s'        = = = '2LLLrT   r*   r  c                   *    e Zd ZddZd Zej        ZdS )rK   r   Nc                 X    t                               | |           || _        || _        d S rV   )r4  r   _context_check_hostname)r   r8  r?   check_hostnames       rS   r   zHTTPSHandler.__init__i  s-    ((z:::#DM#1D   rT   c                 f    |                      t          j        j        || j        | j                  S )N)r?   re  )r   r  r  r  rc  rd  r_  s     rS   
https_openzHTTPSHandler.https_openn  s3    << ;S
d6J   L L 
LrT   )r   NN)r   r   r   r   rg  r4  rI  r  r   rT   rS   rK   rK   g  s>        	2 	2 	2 	2
	L 	L 	L ,7


rT   rK   c                   *    e Zd ZddZd Zd ZeZeZdS )r   Nc                 R    dd l }||j                                        }|| _        d S r  )http.cookiejar	cookiejar	CookieJar)r   rk  r  s      rS   r   zHTTPCookieProcessor.__init__w  s2    0022I"rT   c                 :    | j                             |           |S rV   )rk  add_cookie_headerr?  s     rS   r  z HTTPCookieProcessor.http_request}  s    ((111rT   c                 <    | j                             ||           |S rV   )rk  extract_cookies)r   r   r   s      rS   r4  z!HTTPCookieProcessor.http_response  s    &&x999rT   rV   )r   r   r   r   r  r4  r  r6  r   rT   rS   r   r   v  sL        # # # #     !M"NNNrT   r   c                       e Zd Zd ZdS )r/   c                 4    |j         }t          d|z            )Nzunknown url type: %s)r   r   )r   r  r   s      rS   r
  zUnknownHandler.unknown_open  s    x-4555rT   N)r   r   r   r
  r   rT   rS   r/   r/     s#        6 6 6 6 6rT   r/   c                     i }| D ]B}|                     dd          \  }}|d         dk    r|d         dk    r
|dd         }|||<   C|S )z>Parse list of key=value strings where keys are not duplicated.=r_   r   r  r\   )r  )lparsedeltrD  rE  s        rS   r  r    sc    
F  yya  1Q43;;1R5C<<!B$Aq		MrT   c                     g }d}dx}}| D ]P}|r||z
  }d}|r|dk    rd}|dk    rd}||z
  }%|dk    r|                     |           d}C|dk    rd}||z
  }Q|r|                     |           d |D             S )ap  Parse lists as described by RFC 2068 Section 2.

    In particular, parse comma-separated lists where the elements of
    the list may include quoted-strings.  A quoted-string could
    contain a comma.  A non-quoted string could have quotes in the
    middle.  Neither commas nor quotes count if they are escaped.
    Only double-quotes count, not single-quotes.
    r   F\Tr  r  c                 6    g | ]}|                                 S r   )r  )rC  parts     rS   
<listcomp>z#parse_http_list.<locals>.<listcomp>  s     )))TDJJLL)))rT   )rk   )r
  resr{  escaper
   curs         rS   r  r    s     
C
DFU   	CKDF 	d{{CKD#::JJtD#::E  

4))S))))rT   c                   $    e Zd Zd ZdZd Zd ZdS )r+   c                     |j         }|d d         dk    rL|dd         dk    r>|j        r7|j        dk    r,|j        |                                 vrt          d          d S |                     |          S )Nr;   rf  r  rQ  	localhost-file:// scheme is supported only on localhost)r   r   	get_namesr   open_local_file)r   r  rN   s      rS   	file_openzFileHandler.file_open  s    lrr7d??s1Q3x3CHK''8t~~////NOOO 0/ '',,,rT   Nc                 X   t           j        	 t          t          j        d          d         t          j        t          j                              d         z             t           _        n4# t          j        $ r" t          j        d          ft           _        Y nw xY wt           j        S )Nr  r;   )r+   namesr  r  gethostbyname_exgethostnamegaierror
gethostbynamer   s    rS   r  zFileHandler.get_names  s    $
I$)+K88;+F,>,@,@AA!DE%F %F!! ? 
I 
I 
I%+%9+%F%F$H!!!
I  s   AA, ,.BBc                 b   dd l }dd l}|j        }|j        }t	          |          }	 t          j        |          }|j        }|j        	                    |j
        d          }	|                    |          d         }
 |j        d|
pd||	fz            }|rt          |          \  }}|r%|sRt          |          |                                 v r/|r	d|z   |z   }
nd|z   }
t!          t#          |d          ||
          S n!# t$          $ r}t'          |          d }~ww xY wt'          d          )	Nr   Tusegmtz6Content-type: %s
Content-length: %d
Last-modified: %s

text/plainfile://rbzfile not on local host)email.utils	mimetypesr   r   r5   rd   statst_sizeutils
formatdatest_mtime
guess_typemessage_from_stringr   _safe_gethostbynamer  r   rM   r}   r   )r   r  emailr  r   rp   	localfilestatsrx   modifiedmtypert   r  origurlexps                  rS   r  zFileHandler.open_local_file  ss   x< **		 GI&&E=D{--enT-JJH((2215E/e/K&,h789 9G  
.'--
d 
K
K1$774>>;K;KKK 3'$.9GG'(2G!$y$"7"7'JJJ 	  	  	 3--	 /000s   CD 
DDD)r   r   r   r  r  r  r  r   rT   rS   r+   r+     sH        - - - 
E! ! !1 1 1 1 1rT   r+   c                 X    	 t          j        |           S # t           j        $ r Y d S w xY wrV   )r  r  r  )r   s    rS   r  r    s<    #D)))?   tts    ))c                       e Zd Zd Zd ZdS )r,   c                    dd l }dd l}|j        }|st          d          t	          |          \  }}||j        }nt
          |          }t          |          \  }}|rt          |          \  }}nd }t          |          }|pd}|pd}	 t          j        |          }n!# t          $ r}t          |          d }~ww xY wt          |j                  \  }	}
|	                    d          }t!          t#          t          |                    }|d d         |d         }}|r|d         s
|dd          }	 |                     ||||||j                  }
|rdpd}|
D ]D}t)          |          \  }}|                                d	k    r|d
v r|                                }E|
                    ||          \  }}d}|                    |j                  d         }|r|d|z  z
  }||dk    r|d|z  z
  }t5          j        |          }t9          |||j                  S # |j        $ r}t          |          |d }~ww xY w)
Nr   ftp error: no host givenr   rQ  r\   r_   r  Dr   aAr   r  r)  r  zContent-type: %s
zContent-length: %d
)ftplibr  r   r   r   FTP_PORTrl   r   r   r   r  r  r}   r   r   r  r   mapconnect_ftprP   r   r   upperretrfiler  r   r  r  r   
all_errors)r   r  r  r  r   r  ro  r  r3  re   attrsdirsrX   fwr   attrr   rs   retrlenrt   r  r  s                         rS   ftp_openzFTPHandler.ftp_open  s   


x 	75666%%
d<?DDt99D  %%
d 	'--LD&&Ft}}zr2	 '--DD 	  	  	 3--	  ..ezz#C&&''#2#YRd 	Q 	8D	)!!$dD#+NNB<C&3D 
) 
))$//e::<<6))::: ;;==D++dD11KBG((66q9E 
8/%77"w!||1G;;/88Gb'3<888  	) 	) 	)3--S(	)s1   
B" "
C ,B;;C 8C*H# #
I-H==Ic           	      .    t          ||||||d          S )NF)
persistent)
ftpwrapper)r   ro  r  r   r  r  rP   s          rS   r  zFTPHandler.connect_ftp0  s(    $dD'%*, , , 	,rT   N)r   r   r   r  r  r   rT   rS   r,   r,     s3        2) 2) 2)h, , , , ,rT   r,   c                   2    e Zd Zd Zd Zd Zd Zd Zd ZdS )r-   c                 L    i | _         i | _        d| _        d| _        d| _        d S )Nr   <   r  )cacherP   soonestdelay	max_connsr   s    rS   r   zCacheFTPHandler.__init__7  s)    

rT   c                     || _         d S rV   )r  )r   ts     rS   
setTimeoutzCacheFTPHandler.setTimeout>  s
    


rT   c                     || _         d S rV   )r  )r   rJ  s     rS   setMaxConnszCacheFTPHandler.setMaxConnsA  s
    rT   c                 P   |||d                     |          |f}|| j        v r$t          j                    | j        z   | j        |<   n?t          ||||||          | j        |<   t          j                    | j        z   | j        |<   |                                  | j        |         S )NrQ  )joinr  r  r  rP   r  check_cache)r   ro  r  r   r  r  rP   r   s           rS   r  zCacheFTPHandler.connect_ftpD  s    D$7$* $	dj 8DL(vtT)-w8 8DJsO $	dj 8DLz#rT   c                    t          j                     }| j        |k    rat          | j                                                  D ]:\  }}||k     r/| j        |                                          | j        |= | j        |= ;t          t          | j                                                            | _        t          | j                  | j
        k    rt          | j                                                  D ]"\  }}|| j        k    r| j        |= | j        |=  n#t          t          | j                                                            | _        d S d S rV   )r  r  r   rP   r   r  r   minvaluesrn   r  )r   r  rD  rE  s       rS   r  zCacheFTPHandler.check_cacheO  s8   IKK<1T\//1122 
( 
(1q55JqM'')))
1
Q4 3 3 5 56677 tz??dn,,T\//1122 
 
1$$
1
QE % tDL$7$7$9$9::;;DLLL
 -,rT   c                     | j                                         D ]}|                                 | j                                          | j                                         d S rV   )r  r  r   clearrP   )r   conns     rS   clear_cachezCacheFTPHandler.clear_cachec  s\    J%%'' 	 	DJJLLLL
rT   N)	r   r   r   r   r  r  r  r  r  r   rT   rS   r-   r-   4  sn              	 	 	< < <(    rT   r-   c                       e Zd Zd ZdS )r.   c                    |j         }|                    dd          \  }}|                    dd          \  }}t          |          }|                    d          rt	          j        |          }|d d         }|sd}t
          j        d|t          |          fz            }t          t          j        |          ||          S )Nr}  r_   r  z;base64itext/plain;charset=US-ASCIIz$Content-type: %s
Content-length: %d
)r   r  r   endswithr  decodebytesr  r  rn   r   ioBytesIO)r   r  rN   rV  rO   	mediatypert   s          rS   	data_openzDataHandler.data_openj  s     lyyQ''**S++	4  %%i(( 	'%d++D!#2#I 	65I+,T
D		"-# $ $ "*T**GS999rT   N)r   r   r   r  r   rT   rS   r.   r.   i  s#        : : : : :rT   r.   r;  nt)r5   r4   c                      t          |           S )zOS-specific conversion from a relative URL of the 'file' scheme
        to a file system path; not recommended for general use.)r   pathnames    rS   r5   r5     s     x   rT   c                      t          |           S )zOS-specific conversion from a file system path to a relative URL
        of the 'file' scheme; not recommended for general use.)r
   r  s    rS   r4   r4     s     XrT   c                       e Zd ZdZdZdez  ZddZd Zd Z	d Z
d Zdd	Zdd
Z
ddZddZd
 ZddZddZd Zerd ZddZd Zd Zd ZddZdS )r9   a,  Class to open URLs.
    This is a class rather than just a subroutine because we may need
    more than one set of global protocol-specific options.
    Note -- this is a base class for those who don't want the
    automatic handling of errors type 302 (relocated) and 401
    (authorization needed).Nr   c                    dd| j         j        iz  }t          j        |t          d           |t                      }t
          |d          s
J d            || _        |                    d          | _	        |                    d          | _
        d	| j        fd
g| _        g | _
        t          j        | _        d | _        t$          | _        d S )NzW%(class)s style of invoking requests is deprecated. Use newer urlopen functions/methodsclassr  )
stacklevelru  rv  key_file	cert_filez
User-Agent)Acceptz*/*)r  r   rA   rB   rC   r6   r   rz  r   r  r  versionr   _URLopener__tempfilesrd   r|   _URLopener__unlink	tempcacheftpcache)r   rz  x509r3  s       rS   r   zURLopener.__init__  s    47>@W6XY
c-!<<<<? llGw''DD)DDDD,,
+..($,79JK	
 !


rT   c                 .    |                                   d S rV   )r   r   s    rS   __del__zURLopener.__del__  s    

rT   c                 .    |                                   d S rV   )cleanupr   s    rS   r   zURLopener.close  s    rT   c                     | j         r:| j         D ](}	 |                     |           # t          $ r Y %w xY w| j         d d = | j        r| j                                         d S d S rV   )r  r  r}   r  r  )r   rX   s     rS   r  zURLopener.cleanup  s      	$( 
 
MM$''''   D #> 	#N  """""	# 	#s   (
55c                 :    | j                             |           dS )zdAdd a header to be used by the HTTP interface only
        e.g. u.addheader('Accept', 'sound/basic')N)r   rk   )r   r   s     rS   	addheaderzURLopener.addheader  s      	
t$$$$$rT   c                 .   t          t          |                    }t          |d          }| j        r:|| j        v r1| j        |         \  }}t	          |d          }t          |||          S t
          |          \  }}|sd}|| j        v r6| j        |         }t
          |          \  }}	t          |	          \  }
}|
|f}nd}d|z   }|| _	        |
                    dd          }t          | |          r|d	k    r/|r|                     |||          S | 
                    ||          S 	 | t          | |          |          S  t          | |          ||          S # t          t           f$ r  t"          $ r}
t#          d
|
          |
d}
~
ww xY w)z6Use URLopener().open(file) instead of open(file, 'r').z%/:=&?~#+!$,;'@()*[]|rS  r  rX   Nopen_-r   r  zsocket error)r	   r   r
   r  rM   r   r   rz  r
   r   rH  r   open_unknown_proxyopen_unknownr   r   r   r}   )r   r  rO   rp   rt   rs   urltyperN   rh  	proxyhostr   r   ri   r3  s                 rS   rM   zURLopener.open  s   7++,,&=>>>> 	4g77 $w 7Hgh%%Bb'7333!'** 	Gdl""L)E!+E!2!2GY'	22ND(/CCE 	||C%%tT"" 	8d.?&?&? 
8..ugtDDD(($777	8|*wtT**3///*wtT**35558$ 	 	 	 	8 	8 	8.#..C7	8s   .E# 	E# #F>FFc                 H    t          |          \  }}t          dd|          )/Overridable interface to open unknown URL type.	url errorzunknown url typer   r}   )r   r  rO   r   rN   s        rS   r  zURLopener.open_unknown  s&    w''	ck#5t<<<rT   c                 N    t          |          \  }}t          dd|z  |          )r  r  zinvalid proxy for %sr  )r   rh  r  rO   r   rN   s         rS   r  zURLopener.open_unknown_proxy  s+    w''	ck#9D#@%HHHrT   c                    t          t          |                    }| j        r|| j        v r
| j        |         S t          |          \  }}|z|r|dk    rr	 |                     |          }|                                }|                                 t          t          |          d                   |fS # t          $ r Y nw xY w| 
                    ||          }	 |                                }	|rt          |d          }
nt          |          \  }}t          |pd          \  }}t          |pd          \  }}t          |pd          \  }}t          j                            |          d         }
t!          j        |
          \  }}| j                            |           t          j        |d          }
	 ||	f}| j        
|| j        |<   d}d}d}d}d	|	v rt+          |	d
                   }|r
 ||||           	 |                    |          }|sn<|t/          |          z
  }|
                    |           |dz
  }|r
 ||||           T	 |
                                 n# |
                                 w xY w	 |                                 n# |                                 w xY w|dk    r||k     rt3          d||fz  |          |S )ztretrieve(url) returns (filename, headers) for a local object
        or (tempfilename, headers) for a remote object.NrX   r_   rY   r   r[   r\   r   r]   r^   r`   )r	   r   r  r   r  rc   r   r5   r
   r}   rM   r   r   rd   re   splitextrg   mkstempr  rk   fdopenrl   rm   rn   ro   r   )r   rN   rp   rq   rO   r   url1rs   r   rt   ru   garbagere   suffixfdrv   rw   rx   rm   ry   rz   s                        rS   retrievezURLopener.retrieve  s    Ys^^$$> 	'cT^33>#&&__
dTTV^^
))$//wwyy


#Jt$4$4Q$788$>> 
 
 


YYsD
!
!%	ggiiG 

*8T** *3
 *4:2 6 6
 +DJB 7 7
g *4:2 6 6
g))$//2!)!1&!9!9X ''111iD))
!7*>-*0DN3'#w..w'7899D 3JxT2227GGBKKE  CJJ&DIIe$$$MH! 7"
8R6667  				HHJJJJBHHJJJJ 199&C, &( ( 
( 
s9   A B8 8
CCC J  BI0 J 0JJ J5c                 <   d}d}t          |t                    r8t          |          \  }}|r!t          |          \  }}t	          |          }|}n|\  }}t          |          \  }}t          |          \  }	}
|
}d}|	                                dk    rd}nBt          |
          \  }}
|rt          |          \  }}|r	|	d||
}t          |          r|}|st          dd          |rIt	          |          }t          j
        |                                                              d          }nd}|rIt	          |          }t          j
        |                                                              d          }nd} ||          }
i }|rd|z  |d<   |rd|z  |d	<   |r||d
<   d|d<   | j
        D ]
\  }}|||<   |d
|d<   |
                    d|||           n|
                    d||           	 |
                                }n'# t           j        j        $ r t'          d          w xY wd|j        cxk    rdk     r"n nt+          ||j        d|z   |j                  S |                     ||j        |j        |j        |j        |          S )a  Make an HTTP connection using connection_class.

        This is an internal method that should be called from
        open_http() or open_https().

        Arguments:
        - connection_factory should take a host name and return an
          HTTPConnection instance.
        - url is the url to retrieval or a host, relative-path pair.
        - data is payload for a POST request or None.
        Nr  z://z
http errorrA  r~  zBasic %sr1  r  r   r   rL  rB  zContent-Typer   r   rO  z$http protocol error: bad status liner0  r1  http:)r  r  r
   r   r   r   r   r  r}   r  r  r  r  r   r   rT  r  r  
BadStatusLiner   statusr   r3  
http_errorrs   rV  )r   connection_factoryrN   rO   user_passwdproxy_passwdr   r   realhostr  r   
proxy_authr  	http_connrt   r  r   r   s                     rS   _open_generic_httpzURLopener._open_generic_httpO  s:    c3 	$'__ND( 
%$.t$4$4!Tt}}HH ND(!+D!1!1L$&x00MGTCK}}&((!+D!1!1$ A,6x,@,@)K G.5ggxxFH)) $#DA7<AAA 	"<00L),*=*=*?*?@@GGPPJJJ 	!+..K#K$6$6$8$899@@IIDDD&&t,,	 	E-7*-DG)* 	:(2T(9GO$ 	'&GFO
 !(!_ 	$ 	$MFE#GFOO&IGN#fhg>>>>eXw???	C ,,..HH{( 	C 	C 	CABBB	C (/''''C'''''hgm&o/ / 
/ ??X[(,F F 
Fs    H $H9c                 N    |                      t          j        j        ||          S )zUse HTTP protocol.)r  r  r  r=  r   rN   rO   s      rS   	open_httpzURLopener.open_http  s    &&t{'A3MMMrT   c                     d|z  }t          | |          r6t          | |          }| ||||||          }	n |||||||          }	|	r|	S |                     |||||          S )zHandle http errors.

        Derived class can override this, or provide specific handlers
        named http_error_DDD where DDD is the 3-digit error code.z
http_error_%d)r   r   r  )
r   rN   rs   errcodeerrmsgrt   rO   ri   r   rv   s
             rS   r  zURLopener.http_error  s     (4 	%T4((F|R&'BBR&'4HH$f}&&sBIIIrT   c                 P    |                                  t          ||||d          )z>Default error handler: close the connection and raise OSError.N)r   r   r   rN   rs   r  r  rt   s         rS   r  zURLopener.http_error_default  s%    



Wfgt<<<rT   c                 Z    t           j                            || j        | j                  S )N)r  r  )r  r  r  r  r  )r   r   s     rS   _https_connectionzURLopener._https_connection  s0    ;..t48M59^ / E E 
ErT   c                 :    |                      | j        ||          S )zUse HTTPS protocol.)r  r  r  s      rS   
open_httpszURLopener.open_https  s    **4+A3MMMrT   c                 
   t          |t                    st          d          |dd         dk    r=|dd         dk    r/|dd                                         dk    rt	          d	          |                     |          S )
z/Use local file or FTP depending on form of URL.zEfile error: proxy support for file protocol currently not implementedNr;   rf  r  rQ     z
localhost/r  )r  r  r   r   rD   r  r   s     rS   	open_filezURLopener.open_file  s    #s## 	dbcccrr7d??s1Q3x33qt9??3D3D3T3TLMMM'',,,rT   c                 N   ddl }ddl}t          |          \  }}t          |          }	 t	          j        |          }n,# t          $ r}t          |j        |j	                  d}~ww xY w|j
        }	|j                            |j
        d          }
|                    |          d         } |j        d|pd|	|
fz            }|s4|}
|dd         dk    rd	|z   }
t!          t#          |d
          ||
          S t%          |          \  }}|st'          j        |          t+                      ft-                      z   v rU|}
|dd         dk    rd	|z   }
n |dd         dk    rt/          d
|z            t!          t#          |d
          ||
          S t          d          )zUse local file.r   NTr  z6Content-Type: %s
Content-Length: %d
Last-modified: %s
r  r_   rQ  r  r  r;   z./zAlocal file url may start with / or file:. Unknown url of type: %sz#local file error: not on local host)r  r  r
   r5   rd   r  r}   r   strerrorrp   r  r  r  r  r  r  r   rM   r   r  r  r  thishostrD   )r   rN   r  r  r   rX   	localnamer  erx   r  r  rt   urlfiler  s                  rS   r  zURLopener.open_local_file  s   __
d &&		3GI&&EE 	3 	3 	31:qz222	3};))%.)FF$$S))!,+%+G

"lD(3
45 5  	GGBQBx3#d*d9d33WgFFF%%
d 	G#D))y{{nxzz.IJJGBQBx3#d*bqbT!! !dgj!jkkkd9d33WgFFF<===s   A   
A)
A$$A)c                    t          |t                    st          d          ddl}t	          |          \  }}|st          d          t          |          \  }}t
          |          \  }}|rt          |          \  }}nd}t          |          }t          |pd          }t          |pd          }t          j
        |          }|sddl}|j        }nt          |          }t          |          \  }}	t          |          }|                    d          }
|
dd         |
d         }}
|
r|
d         s
|
dd         }
|
r
|
d         sd|
d<   |||d                    |
          f}t#          | j                  t&          k    rFt)          | j                  D ]1}
|
|k    r)| j        |
         }| j        |
= |                                 2	 || j        vrt-          |||||
          | j        |<   |sd	}nd
}|	D ]D}t/          |          \  }}|                                dk    r|dv r|                                }E| j        |                             ||          \  }}|                    d
|z             d         }d}|r|d|z  z
  }||dk    r|d|z  z
  }t9          j        |          }t=          ||d
|z             S # t?                      $ r}t          d|           |d}~ww xY w)zUse FTP protocol.zCftp error: proxy support for ftp protocol currently not implementedr   Nr  r   rQ  r\   r_   r  r  r   r  zftp:zContent-Type: %s
zContent-Length: %d
ftp error: ) r  r  r   r  r
   r   r   r   r   r  r  r  r  rl   r   r  r  rn   r  MAXFTPCACHEr   r   r  r   r   r  r  r  r  r  r   	ftperrors)r   rN   r  r   re   r  ro  r  r  r  r  rX   r   rD  rE  r   r  r   rs   r  r  rt   r  s                          rS   open_ftpzURLopener.open_ftp  sE   #s## 	b`aaa__
d?8$>???%%
d%%
d 	T 2 2vvft}}tzr""2&&#D)) 	MMM?DDt99D &&et}}zz##2#YRd0Q0QRR.Q.3aD$.t}++$-(( 
 
88
a(A
a(GGIII	9$-''tVT4>> 
c" 
$ 
) 
))$//e::<<6))::: ;;==D M#.77dCCMR((#66q9EG 
8/%77"w!||1G;;/88Gb'6C<888{{ 	9 	9 	9...//S8	9s   C7K	 	K2K--K2c           
         t          |t                    st          d          	 |                    dd          \  }}n# t          $ r t          dd          w xY w|sd}|                    d          }|dk    r$d	||d
         vr||dz   d
         }|d
|         }nd}g }|                    dt          j	        d
t          j
        t          j                                        z             |                    d|z             |dk    r;t          j        |
                    d                                        d          }nt          |          }|                    dt!          |          z             |                    d           |                    |           d                    |          }t%          j        |          }t)          j        |          }t-          |||          S )zUse "data" URL.zEdata error: proxy support for data protocol currently not implementedr  r_   z
data errorzbad data URLr  ;r   rt  Nr   zDate: %sz%a, %d %b %Y %H:%M:%S GMTzContent-type: %sr  r~  zlatin-1zContent-Length: %d
)r  r  r   r  rD   r}   rfindrk   r  strftimegmtimer  r  r  r  r   rn   r  r  r  r  StringIOr   )	r   rN   rO   r   semirR  r3  rt   fs	            rS   	open_datazURLopener.open_data1  s   #s## 	dbccc	899S!,,LT44 	8 	8 	8,777	8 	10Dzz#199DK//DFGG}H;DDH

:dm,G,0K	,D,DF F F 	G 	G 	G

%,---x%dkk'&:&:;;BB9MMDD4==D

'#d))3444

2

4iinn+C00K!Wc***s   A   ArV   NNN)r   r   r   r5  r  r   r  r   r  r   r  r  rM   r  r  r	  r  r  r  r  rE   r  r!  r$  r  r/  r9  r   rT   rS   r9   r9     s         K ;.G! ! ! !4    # # #% % %"8 "8 "8 "8H= = = =
I I I I= = = =BZF ZF ZFxN N N NJ J J J = = =
  N	E 	E 	E
	N 	N 	N 	N- - -> > >@89 89 89t'+ '+ '+ '+ '+ '+rT   r9   c                       e Zd ZdZd Zd ZddZd ZddZddZ	dd	Z
dd
Z	 	 ddZ	 	 dd
Z
ddZddZddZddZddZd ZdS )r:   z?Derived class with handlers for errors we can handle (perhaps).c                 Z    t          j        | g|R i | i | _        d| _        d| _        d S )Nr   r;  )r9   r   
auth_cachetriesmaxtries)r   r   r  s      rS   r   zFancyURLopener.__init__^  s<    41$111&111



rT   c                 ,    t          ||d|z   |          S )z3Default error handling -- don't raise an exception.r  )r   r  s         rS   r  z!FancyURLopener.http_error_defaultd  s    "gw}g>>>rT   Nc                    | xj         dz
  c_         	 | j        rE| j         | j        k    r5t          | d          r| j        }n| j        } |||dd|          d| _         S |                     ||||||          }|d| _         S # d| _         w xY w)z%Error 302 -- relocated (temporarily).r_   http_error_500r&  z)Internal Server Error: Redirect Recursionr   )r>  r?  r   rB  r  redirect_internal)	r   rN   rs   r  r  rt   rO   r   rv   s	            rS   r`  zFancyURLopener.http_error_302h  s    

a


	} 
%t}!<!<4!122 3.DD2DtCSG#% % DJJ	 ++CWf,3T; ;FDJJDJNNNNs   AB B 	B
c                 $   d|v r	|d         }nd|v r	|d         }nd S |                                  t          | j        dz   |z   |          }t          |          }|j        dvrt          |||d|z  z   ||          |                     |          S )NrM  rN  r}  rO  z( Redirection to url '%s' is not allowed.)r   r   r   r   rV  r   rM   )	r   rN   rs   r  r  rt   rO   rI  r]  s	            rS   rC  z FancyURLopener.redirect_internalz  s      Z(FF
g

U^FFF



 S3.77F## ?">>>FG"FOP#R) ) 
)
 yy   rT   c                 6    |                      ||||||          S )z*Error 301 -- also relocated (permanently).r`  r   rN   rs   r  r  rt   rO   s          rS   ra  zFancyURLopener.http_error_301       ""3GVWdKKKrT   c                 6    |                      ||||||          S )z;Error 303 -- also relocated (essentially identical to 302).rF  rG  s          rS   rb  zFancyURLopener.http_error_303  rH  rT   c                 l    ||                      ||||||          S |                     |||||          S )z1Error 307 -- relocated, but turn POST into error.)r`  r  rG  s          rS   rc  zFancyURLopener.http_error_307  A    <&&sB$OOO**3GVWMMMrT   c                 l    ||                      ||||||          S |                     |||||          S )z1Error 308 -- relocated, but turn POST into error.)ra  r  rG  s          rS   rd  zFancyURLopener.http_error_308  rK  rT   Fc                 *   d|vrt                               | |||||           |d         }t          j        d|          }	|	st                               | |||||           |	                                \  }
}|
                                dk    rt                               | |||||           |st                               | |||||           d| j        z   dz   }| t          | |          ||          S  t          | |          |||          S )z_Error 401 -- authentication required.
        This function supports Basic authentication only.r  ![ 	]*([^ 	]+)[ 	]+realm="([^"]*)"r  retry__basic_authr9   r  r  matchr  r   r   r   
r   rN   rs   r  r  rt   rO   r/  stuffrR  rV  r  ri   s
                rS   r  zFancyURLopener.http_error_401  sN    W,,((sB)0&'
C 
C 
C*+?GG 	C((sB)0&'
C 
C 
C
<<>>W$$((sB)0&'
C 
C 
C 	((sB
 
 
$)#m3<%74%%c5111%74%%c5$777rT   c                 *   d|vrt                               | |||||           |d         }t          j        d|          }	|	st                               | |||||           |	                                \  }
}|
                                dk    rt                               | |||||           |st                               | |||||           d| j        z   dz   }| t          | |          ||          S  t          | |          |||          S )zeError 407 -- proxy authentication required.
        This function supports Basic authentication only.r  rN  r  retry_proxy_rP  rQ  rS  s
                rS   r  zFancyURLopener.http_error_407  sN     w..((sB)0&'
C 
C 
C,-?GG 	C((sB)0&'
C 
C 
C
<<>>W$$((sB)0&'
C 
C 
C 	((sB
 
 
	)M9<%74%%c5111%74%%c5$777rT   c                    t          |          \  }}d|z   |z   }| j        d         }t          |          \  }}	t          |	          \  }	}
|	                    d          dz   }|	|d          }	|                     |	||          \  }}
|s|
sd S t          |d          dt          |
d          d|	}	d|	z   |
z   | j        d<   ||                     |          S |                     ||          S )Nhttp://r  rg  r_   r   r  r}  r
   rz  r   r   get_user_passwdr
   rM   r   rN   r  rO   r   r   rI  rh  r  r  
proxyselectorr   ro  r  s                 rS   retry_proxy_http_basic_authz*FancyURLopener.retry_proxy_http_basic_auth  s   #ChT!H,V$'..#-i#8#8 	=NN3!#abbM	++Iua@@f,,"'2"6"6"6"6"6"'R"8"8"8"8"8))E	(94}DV<99V$$$99VT***rT   c                    t          |          \  }}d|z   |z   }| j        d         }t          |          \  }}	t          |	          \  }	}
|	                    d          dz   }|	|d          }	|                     |	||          \  }}
|s|
sd S t          |d          dt          |
d          d|	}	d|	z   |
z   | j        d<   ||                     |          S |                     ||          S )Nhttps://r   rg  r_   r   r  r}  rY  r[  s                 rS   retry_proxy_https_basic_authz+FancyURLopener.retry_proxy_https_basic_auth  s   #Chd"X-W%'..#-i#8#8 	=NN3!#abbM	++Iua@@f,,"'2"6"6"6"6"6"'R"8"8"8"8"8))E	 *Y 6 FW<99V$$$99VT***rT   c                 d   t          |          \  }}|                    d          dz   }||d          }|                     |||          \  }}|s|sd S t          |d          dt          |d          d|}d|z   |z   }	||                     |	          S |                     |	|          S )Nrg  r_   r   r  r}  rX  r
   r   rZ  r
   rM   
r   rN   r  rO   r   r   r   ro  r  rI  s
             rS   r  z$FancyURLopener.retry_http_basic_auth	  s    #ChIIcNNQABBx++D%;;f,,"4b11111"633333TT;T!H,<99V$$$99VT***rT   c                 d   t          |          \  }}|                    d          dz   }||d          }|                     |||          \  }}|s|sd S t          |d          dt          |d          d|}d|z   |z   }	||                     |	          S |                     |	|          S )Nrg  r_   r   r  r}  r_  rb  rc  s
             rS   retry_https_basic_authz%FancyURLopener.retry_https_basic_auth	  s    #ChIIcNNQABBx++D%;;f,,"4b11111"633333TT;d"X-<99V$$$99VT***rT   r   c                     |dz   |                                 z   }|| j        v r|r	| j        |= n
| j        |         S |                     ||          \  }}|s|r||f| j        |<   ||fS )Nrg  )r   r=  prompt_user_passwd)r   r   r  r  r   ro  r  s          rS   rZ  zFancyURLopener.get_user_passwd	  s    ckDJJLL($/!! 
,OC((s++..tU;;f@6@4.4?3/V|rT   c           	          ddl }	 t          d|d|d          }|                     d|d|d|d          }||fS # t          $ r t                       Y dS w xY w)	z#Override this in a GUI environment!r   NzEnter username for z at z: zEnter password for z in r  )getpassinputKeyboardInterruptprint)r   r   r  ri  ro  r  s         rS   rg  z!FancyURLopener.prompt_user_passwd)	  s    	5EEE444HIID___uuuddd&$ % %F<  	 	 	GGG::	s   8? AArV   )NFr\  )r   r   r   r5  r   r  r`  rC  ra  rb  rc  rd  r  r  r]  r`  r  re  rZ  rg  r   rT   rS   r:   r:   [  sj       II  ? ? ?   $! ! !8L L L LL L L LN N N NN N N N FJ8 8 8 82 FJ8 8 8 82+ + + +$+ + + +$+ + + ++ + + +	 	 	 	
 
 
 
 
rT   r:   c                  F    t           t          j        d          a t           S )z8Return the IP address of the magic hostname 'localhost'.Nr  )
_localhostr  r  r   rT   rS   r  r  9	  s      )+66
rT   c                  
   t           v	 t          t          j        t          j                              d                   a n<# t          j        $ r* t          t          j        d          d                   a Y nw xY wt           S )z,Return the IP addresses of the current host.Nr;   r  )	_thishostr  r  r  r  r  r   rT   rS   r'  r'  A	  s     	Gf5f6H6J6JKKANOOII 	G 	G 	Gf5kBB1EFFIII	Gs   8A 6A;:A;c                  4    t           ddl} | j        a t           S )z1Return the set of errors raised by the FTP class.Nr   )
_ftperrorsr  r  )r  s    rS   r.  r.  L	  s!     


&
rT   c                  F    t           t          j        d          a t           S )z%Return an empty email Message object.Nr   )
_noheadersr  r  r   rT   rS   	noheadersru  U	  s      .r22
rT   c                   B    e Zd ZdZ	 	 ddZd Zd Zd Zd Zd	 Z	d
 Z
dS )r  z;Class used by open_ftp() for cache of open FTP connections.NTc                     || _         || _        || _        || _        || _        || _        d| _        || _        	 |                                  d S #  | 	                                  xY wr  )
ro  r  r   r  r  rP   refcount	keepaliveinitr   )r   ro  r  r   r  r  rP   r  s           rS   r   zftpwrapper.__init__b	  si    				
#	IIKKKKK	JJLLLs   A A'c                 V   dd l }d| _        |                                | _        | j                            | j        | j        | j                   | j                            | j	        | j
                   d                    | j                  }| j        
                    |           d S )Nr   rQ  )r  busyFTPrP  connectr   r  rP   loginro  r  r  r  cwd)r   r  _targets      rS   rz  zftpwrapper.initr	  s    


	::<<DIt|<<<ty$+...((49%%WrT   c                 D   dd l }|                                  |dv rd}d}nd|z   }d}	 | j                            |           n># |j        $ r1 |                                  | j                            |           Y nw xY wd }|rk|si	 d|z   }| j                            |          \  }}nE# |j        $ r8}t          |          d d         dk    rt          d	|           |Y d }~nd }~ww xY w|s| j                            d           |r| j        
                                }		 	 | j                            |           n%# |j        $ r}t          d
|z            |d }~ww xY w	 | j                            |	           n# | j                            |	           w xY wd|z   }nd}| j                            |          \  }}d| _        t          |                    d
          | j                  }
| xj        dz
  c_        |                                 |
|fS )Nr   )r)  r  zTYPE Ar_   zTYPE zRETR r  550r,  z
ftp error: %rzLIST LISTr  )r  endtransferrP  voidcmdr  rz  ntransfercmd
error_permr  r   pwdr  r|  r   makefile
file_closerx  r   )r   rX   r   r  cmdisdirr  r  rV  r  ftpobjs              rS   r  zftpwrapper.retrfile{	  s   


:XsquudNcAE	"HS!!!!  	" 	" 	"IIKKKHS!!!!!	"  	G 	G
Gn $ 5 5c : :
gg$ 
G 
G 
Gv;;rr?e++"#9#9#9::F ,++++
G  	7HX&&& 
hllnn&MT****!, M M M&'?@@fLM + HLL%%%%DHLL%%%%n H11#66MD'	dmmD114?CC





  sS   A 8B ?B 
"B- -
C/7.C**C/+E F 
E(E##E((F F#c                     d| _         d S r  )r|  r   s    rS   r  zftpwrapper.endtransfer	  s
    			rT   c                 V    d| _         | j        dk    r|                                  d S d S )NFr   )ry  rx  
real_closer   s    rS   r   zftpwrapper.close	  s4    =AOO rT   c                     |                                   | xj        dz  c_        | j        dk    r| j        s|                                  d S d S d S )Nr_   r   )r  rx  ry  r  r   s    rS   r  zftpwrapper.file_close	  s\    



=AdnOO rT   c                     |                                   	 | j                                         d S # t                      $ r Y d S w xY wrV   )r  rP  r   r.  r   s    rS   r  zftpwrapper.real_close	  sW    	HNN{{ 	 	 	DD	s   1 AA)NT)r   r   r   r5  r   rz  r  r  r   r  r  r   rT   rS   r  r  _	  s        EE?C       *! *! *!X    
      rT   r  c                     i } t           j                                        D ]6\  }}|                                }|r|dd         dk    r
|| |dd         <   7dt           j        v r|                     dd           t           j                                        D ]U\  }}|dd         dk    rB|                                }|r|| |dd         <   7|                     |dd         d           V| S )a  Return a dictionary of scheme -> proxy server URL mappings.

    Scan the environment for variables named <scheme>_proxy;
    this seems to be the standard convention.  If you need a
    different way, you can pass a proxies dictionary to the
    [Fancy]URLopener constructor.

    iN_proxyREQUEST_METHODr  )rd   environr   r   r   )rz  ri   r   s      rS   getproxies_environmentr  	  s	    G z'')) ' 'ezz|| 	'T"##Y(**!&GD"I
 2:%%FD!!!z'')) - -e9  ::<<D 
-%*SbS	""D"It,,,NrT   c                    |t                      }	 |d         }n# t          $ r Y dS w xY w|dk    rdS |                                 } t          |           \  }}|                    d          D ]}|                                }|rj|                    d          }|                                }||k    s| |k    r dS d|z   }|                    |          s|                     |          r dS dS )zTest if proxies should not be used for a particular host.

    Checks the proxy dict for the value of no_proxy, which should
    be a list of comma separated DNS suffixes, or '*' for all hosts.

    NnoF*Tr  .)r  r  r   r   r  r  lstripr  )r   rz  no_proxyhostonlyr  ri   s         rS   proxy_bypass_environmentr  	  s    (**4=   uu 3t::<<D%%NHds## 	 	zz|| 	;;s##D::<<D444<<tt:D  && 
$--*=*= 
tt5s    
))c                    ddl m } t          |           \  }}d }d| vr
|d         rdS d}|                    dd	          D ]}|st          j        d
|          }||1	 t          j        |          } ||          }n# t          $ r Y Kw xY w ||                    d                    }	|                    d          }
|
/d
|                    d          	                    d          dz   z  }
nt          |
dd                   }
|
dk     s|
dk    rd|
z
  }
||
z	  |	|
z	  k    r dS  || |          r dS dS )aj  
    Return True iff this host shouldn't be accessed using a proxy

    This function uses the MacOSX framework SystemConfiguration
    to fetch the proxy information.

    proxy_settings come from _scproxy._get_proxy_settings or get mocked ie:
    { 'exclude_simple': bool,
      'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16']
    }
    r   )fnmatchc                    |                      d          }t          t          t          |                    }t	          |          dk    r|g dz   d d         }|d         dz  |d         dz  z  |d         d	z  z  |d
         z  S )Nr  r:  )r   r   r   r   r      r_   r  r;   r  r  )r  r   r  rl   rn   )ipAddrr  s     rS   ip2numz,_proxy_bypass_macosx_sysconf.<locals>.ip2num
  s    S!!Se__%%u::??\\\)2A2.EaB58r>2eAh!mDuQxOOrT   r  exclude_simpleTN
exceptionsr   z(\d+(?:\.\d+)*)(/\d+)?r_   r;   r      F)r  r   r   r  rR  r  r  r}   groupcountrl   )r   proxy_settingsr  r  r  r  hostIPr   rJ  r  masks              rS   _proxy_bypass_macosx_sysconfr  
  s     %%NHdP P P $*+ 	4
F##L"55  hH.66=~#1(;;F#VF^^FF   H 6!''!**%%D771::D|AGGAJJ,,S11A5648}}axx4"999D$DDL11tt 2 WT5
!
! 	44	 5s   !B
B
Bdarwin)_get_proxy_settings_get_proxiesc                 >    t                      }t          | |          S rV   )r  r  )r   r  s     rS   proxy_bypass_macosx_sysconfr  E
  s    ,..+D.AAArT   c                      t                      S )zReturn a dictionary of scheme -> proxy server URL mappings.

        This function uses the MacOSX framework SystemConfiguration
        to fetch the proxy information.
        )r  r   rT   rS   getproxies_macosx_sysconfr  I
  s     ~~rT   c                 `    t                      }|rt          | |          S t          |           S )zReturn True, if host should be bypassed.

        Checks proxy settings gathered from the environment, if specified,
        or from the MacOSX framework SystemConfiguration.

        )r  r  r  r   rz  s     rS   r  r  S
  s5     )** 	5+D':::.t444rT   c                  :    t                      p
t                      S rV   )r  r  r   rT   rS   r6   r6   `
  s    %''F+D+F+FFrT   c                  *   i } 	 ddl }n# t          $ r | cY S w xY w	 |                    |j        d          }|                    |d          d         }|rt          |                    |d          d                   }d|vrd|vrd                    |          }|                    d          D ]J}|                    dd	          \  }}t          j	        d
|          s|dv rd|z   }n|d
k    rd|z   }|| |<   K| 
                    d
          rPt          j        dd| d
                   }| 
                    d          p|| d<   | 
                    d          p|| d<   |                                 n# t          t          t          f$ r Y nw xY w| S )zxReturn a dictionary of scheme -> proxy server URL mappings.

        Win32 uses the registry to store proxies.

        r   N;Software\Microsoft\Windows\CurrentVersion\Internet SettingsProxyEnableProxyServerrt  r1  zhttp={0};https={0};ftp={0}r_   z
(?:[^/:]+)://)r  r   rP  rX  sockszsocks://z	^socks://z	socks4://r  r   )winregImportErrorOpenKeyHKEY_CURRENT_USERQueryValueExr  r   r  r  rR  r   r   Closer}   rD   r   )rz  r  internetSettingsproxyEnableproxyServerpr   addresss           rS   getproxies_registryr  e
  s    	MMMM 	 	 	NNN	"	%~~f.FN P  P --.>/<> >>?AK 
G!&"5"56F7D#F #FFG#I J Jk))c.D.D">"E"Ek"R"RK$**3// 
0 
0A()Q%Hg8OW== ;#'???&/'&9GG%00&07&:G(/GH%%;;w'' G f\;@PQQG&-kk&&9&9&DWGFO'.{{7';';'FwGG$""$$$$Y/ 	 	 	 
D		
 s   	 EE6 6FFc                  :    t                      p
t                      S )zReturn a dictionary of scheme -> proxy server URL mappings.

        Returns settings gathered from the environment, if specified,
        or the registry.

        )r  r  r   rT   rS   r6   r6   
  s     &''@+>+@+@@rT   c                 x   	 dd l }n# t          $ r Y dS w xY w	 |                    |j        d          }|                    |d          d         }t          |                    |d          d                   }n# t          $ r Y dS w xY w|r|sdS t          |           \  }}|g} 	 t          j	        |          }||k    r| 
                    |           n# t          $ r Y nw xY w	 t          j        |          }||k    r| 
                    |           n# t          $ r Y nw xY w|                    d          }|D ]z}	|	dk    rd|vr dS |	
                    dd	          }	|	
                    d
d          }	|	
                    dd          }	| D ]&}
t          j        |	|
t          j                  r  dS '{dS )
Nr   r  r  
ProxyOverrider1  z<local>r  r_   z\.r  z.*?)r  r  r  r  r  r  r}   r   r  r  rk   getfqdnr  rH  r  rR  r  )r   r  r  r  
proxyOverriderawHostr  addrfqdnr  r   s              rS   proxy_bypass_registryr  
  s]   	MMMM 	 	 	11			%~~f.FN P  P --.>/<> >>?AK 3 34D5D!F !FFG!I J JMM  	 	 	11	 	- 	1"4((
y	'00DwD!!! 	 	 	D		>'**DwD!!! 	 	 	D	
 &++C00
! 		 		Dy  g%%11<<U++D<<U++D<<T**D 
 
8D#rt,, 111
 qsB    
A A: :
BB'/C 
C$#C$(/D 
D%$D%c                 `    t                      }|rt          | |          S t          |           S )zReturn True, if host should be bypassed.

        Checks proxy settings gathered from the environment, if specified,
        or the registry.

        )r  r  r  r  s     rS   r  r  
  s5     )** 	/+D':::(...rT   r:  rV   )~r5  r  r   r  r  http.clientr  r  rd   	posixpathr  r  rX  r  r  rg   ra   rA   urllib.errorr   r   r   urllib.parser   r   r   r	   r
   r   r   r
   r   r   r   r   r   r   r   r   r   r   urllib.responser   r   rF   rE   r  __all__version_infor   rL   r  r1   r2   rj   r7   r8   r  ASCIIr   r   r   r   r3   r   r0   r   r   rq  r    r!   r"   r#   r$   r%   r&   urandomr  r'   r(   r)   r4  r*   r   r  rK   rk   r   r/   r  r  r+   r  r,   r-   r.   r-  ri   
nturl2pathr5   r4   r  r9   r:   rn  r  rp  r'  rr  r.  rt  ru  r  r  r  r  platform_scproxyr  r  r  r  r  r6   r  r  r   rT   rS   <module>r     s	  C Cf 


 



       				 				     				 



 



 



        C B B B B B B B B B" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 5 4 4 4 4 4 4 4JJJ II    III
  $ (!,,
F$B M+45$M+ M+ M+ M+ M+^   = = = =~   rz(BH--   k" k" k" k" k" k" k" k"ZI+ I+ I+ I+ I+ I+ I+ I+^" " "H8 8 8 8 8 8 8 8&# # # # # # # #"; ; ; ; ;k ; ; ;n2 n2 n2 n2 n2+ n2 n2 n2b, , ,B)> )> )> )> )>; )> )> )>V=* =* =* =* =* =* =* =*@G G G G Go G G G3 3 3 3 3#B 3 3 3>k# k# k# k# k# k# k# k#^    3[       4k     zO O O O O O O Od    K)B   $
 
 
 
 
[*C 
 
 
s s s s s+ s s sl3 3 3 3 3% 3 3 3 74;)** #8 8 8 8 8* 8 8 8 NN>"""# # # # #+ # # #$6 6 6 6 6[ 6 6 6
  )* )* )*V11 11 11 11 11+ 11 11 11f  7, 7, 7, 7, 7, 7, 7, 7,r3 3 3 3 3j 3 3 3j: : : : :+ : : :B  7d??555555555! ! !
   z+ z+ z+ z+ z+ z+ z+ z+z
X X X X XY X X Xz 
   
	   
   
  [ [ [ [ [ [ [ [|  >       J> > >B <8::::::::B B B  5 5 5G G G G G W__/ / /bA A A0 0 0d/ / / / / (J+LLLs   >B BB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       #
# core.py
#
import os
import typing
from typing import (
    NamedTuple,
    Union,
    Callable,
    Any,
    Generator,
    Tuple,
    List,
    TextIO,
    Set,
    Sequence,
)
from abc import ABC, abstractmethod
from enum import Enum
import string
import copy
import warnings
import re
import sys
from collections.abc import Iterable
import traceback
import types
from operator import itemgetter
from functools import wraps
from threading import RLock
from pathlib import Path

from .util import (
    _FifoCache,
    _UnboundedCache,
    __config_flags,
    _collapse_string_to_ranges,
    _escape_regex_range_chars,
    _bslash,
    _flatten,
    LRUMemo as _LRUMemo,
    UnboundedMemo as _UnboundedMemo,
)
from .exceptions import *
from .actions import *
from .results import ParseResults, _ParseResultsWithOffset
from .unicode import pyparsing_unicode

_MAX_INT = sys.maxsize
str_type: Tuple[type, ...] = (str, bytes)

#
# Copyright (c) 2003-2022  Paul T. McGuire
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#


if sys.version_info >= (3, 8):
    from functools import cached_property
else:

    class cached_property:
        def __init__(self, func):
            self._func = func

        def __get__(self, instance, owner=None):
            ret = instance.__dict__[self._func.__name__] = self._func(instance)
            return ret


class __compat__(__config_flags):
    """
    A cross-version compatibility configuration for pyparsing features that will be
    released in a future version. By setting values in this configuration to True,
    those features can be enabled in prior versions for compatibility development
    and testing.

    - ``collect_all_And_tokens`` - flag to enable fix for Issue #63 that fixes erroneous grouping
      of results names when an :class:`And` expression is nested within an :class:`Or` or :class:`MatchFirst`;
      maintained for compatibility, but setting to ``False`` no longer restores pre-2.3.1
      behavior
    """

    _type_desc = "compatibility"

    collect_all_And_tokens = True

    _all_names = [__ for __ in locals() if not __.startswith("_")]
    _fixed_names = """
        collect_all_And_tokens
        """.split()


class __diag__(__config_flags):
    _type_desc = "diagnostic"

    warn_multiple_tokens_in_named_alternation = False
    warn_ungrouped_named_tokens_in_collection = False
    warn_name_set_on_empty_Forward = False
    warn_on_parse_using_empty_Forward = False
    warn_on_assignment_to_Forward = False
    warn_on_multiple_string_args_to_oneof = False
    warn_on_match_first_with_lshift_operator = False
    enable_debug_on_named_expressions = False

    _all_names = [__ for __ in locals() if not __.startswith("_")]
    _warning_names = [name for name in _all_names if name.startswith("warn")]
    _debug_names = [name for name in _all_names if name.startswith("enable_debug")]

    @classmethod
    def enable_all_warnings(cls) -> None:
        for name in cls._warning_names:
            cls.enable(name)


class Diagnostics(Enum):
    """
    Diagnostic configuration (all default to disabled)
    - ``warn_multiple_tokens_in_named_alternation`` - flag to enable warnings when a results
      name is defined on a :class:`MatchFirst` or :class:`Or` expression with one or more :class:`And` subexpressions
    - ``warn_ungrouped_named_tokens_in_collection`` - flag to enable warnings when a results
      name is defined on a containing expression with ungrouped subexpressions that also
      have results names
    - ``warn_name_set_on_empty_Forward`` - flag to enable warnings when a :class:`Forward` is defined
      with a results name, but has no contents defined
    - ``warn_on_parse_using_empty_Forward`` - flag to enable warnings when a :class:`Forward` is
      defined in a grammar but has never had an expression attached to it
    - ``warn_on_assignment_to_Forward`` - flag to enable warnings when a :class:`Forward` is defined
      but is overwritten by assigning using ``'='`` instead of ``'<<='`` or ``'<<'``
    - ``warn_on_multiple_string_args_to_oneof`` - flag to enable warnings when :class:`one_of` is
      incorrectly called with multiple str arguments
    - ``enable_debug_on_named_expressions`` - flag to auto-enable debug on all subsequent
      calls to :class:`ParserElement.set_name`

    Diagnostics are enabled/disabled by calling :class:`enable_diag` and :class:`disable_diag`.
    All warnings can be enabled by calling :class:`enable_all_warnings`.
    """

    warn_multiple_tokens_in_named_alternation = 0
    warn_ungrouped_named_tokens_in_collection = 1
    warn_name_set_on_empty_Forward = 2
    warn_on_parse_using_empty_Forward = 3
    warn_on_assignment_to_Forward = 4
    warn_on_multiple_string_args_to_oneof = 5
    warn_on_match_first_with_lshift_operator = 6
    enable_debug_on_named_expressions = 7


def enable_diag(diag_enum: Diagnostics) -> None:
    """
    Enable a global pyparsing diagnostic flag (see :class:`Diagnostics`).
    """
    __diag__.enable(diag_enum.name)


def disable_diag(diag_enum: Diagnostics) -> None:
    """
    Disable a global pyparsing diagnostic flag (see :class:`Diagnostics`).
    """
    __diag__.disable(diag_enum.name)


def enable_all_warnings() -> None:
    """
    Enable all global pyparsing diagnostic warnings (see :class:`Diagnostics`).
    """
    __diag__.enable_all_warnings()


# hide abstract class
del __config_flags


def _should_enable_warnings(
    cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str]
) -> bool:
    enable = bool(warn_env_var)
    for warn_opt in cmd_line_warn_options:
        w_action, w_message, w_category, w_module, w_line = (warn_opt + "::::").split(
            ":"
        )[:5]
        if not w_action.lower().startswith("i") and (
            not (w_message or w_category or w_module) or w_module == "pyparsing"
        ):
            enable = True
        elif w_action.lower().startswith("i") and w_module in ("pyparsing", ""):
            enable = False
    return enable


if _should_enable_warnings(
    sys.warnoptions, os.environ.get("PYPARSINGENABLEALLWARNINGS")
):
    enable_all_warnings()


# build list of single arg builtins, that can be used as parse actions
_single_arg_builtins = {
    sum,
    len,
    sorted,
    reversed,
    list,
    tuple,
    set,
    any,
    all,
    min,
    max,
}

_generatorType = types.GeneratorType
ParseAction = Union[
    Callable[[], Any],
    Callable[[ParseResults], Any],
    Callable[[int, ParseResults], Any],
    Callable[[str, int, ParseResults], Any],
]
ParseCondition = Union[
    Callable[[], bool],
    Callable[[ParseResults], bool],
    Callable[[int, ParseResults], bool],
    Callable[[str, int, ParseResults], bool],
]
ParseFailAction = Callable[[str, int, "ParserElement", Exception], None]
DebugStartAction = Callable[[str, int, "ParserElement", bool], None]
DebugSuccessAction = Callable[
    [str, int, int, "ParserElement", ParseResults, bool], None
]
DebugExceptionAction = Callable[[str, int, "ParserElement", Exception, bool], None]


alphas = string.ascii_uppercase + string.ascii_lowercase
identchars = pyparsing_unicode.Latin1.identchars
identbodychars = pyparsing_unicode.Latin1.identbodychars
nums = "0123456789"
hexnums = nums + "ABCDEFabcdef"
alphanums = alphas + nums
printables = "".join([c for c in string.printable if c not in string.whitespace])

_trim_arity_call_line: traceback.StackSummary = None


def _trim_arity(func, max_limit=3):
    """decorator to trim function calls to match the arity of the target"""
    global _trim_arity_call_line

    if func in _single_arg_builtins:
        return lambda s, l, t: func(t)

    limit = 0
    found_arity = False

    def extract_tb(tb, limit=0):
        frames = traceback.extract_tb(tb, limit=limit)
        frame_summary = frames[-1]
        return [frame_summary[:2]]

    # synthesize what would be returned by traceback.extract_stack at the call to
    # user's parse action 'func', so that we don't incur call penalty at parse time

    # fmt: off
    LINE_DIFF = 7
    # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND
    # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!!
    _trim_arity_call_line = (_trim_arity_call_line or traceback.extract_stack(limit=2)[-1])
    pa_call_line_synth = (_trim_arity_call_line[0], _trim_arity_call_line[1] + LINE_DIFF)

    def wrapper(*args):
        nonlocal found_arity, limit
        while 1:
            try:
                ret = func(*args[limit:])
                found_arity = True
                return ret
            except TypeError as te:
                # re-raise TypeErrors if they did not come from our arity testing
                if found_arity:
                    raise
                else:
                    tb = te.__traceback__
                    trim_arity_type_error = (
                        extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth
                    )
                    del tb

                    if trim_arity_type_error:
                        if limit < max_limit:
                            limit += 1
                            continue

                    raise
    # fmt: on

    # copy func name to wrapper for sensible debug output
    # (can't use functools.wraps, since that messes with function signature)
    func_name = getattr(func, "__name__", getattr(func, "__class__").__name__)
    wrapper.__name__ = func_name
    wrapper.__doc__ = func.__doc__

    return wrapper


def condition_as_parse_action(
    fn: ParseCondition, message: str = None, fatal: bool = False
) -> ParseAction:
    """
    Function to convert a simple predicate function that returns ``True`` or ``False``
    into a parse action. Can be used in places when a parse action is required
    and :class:`ParserElement.add_condition` cannot be used (such as when adding a condition
    to an operator level in :class:`infix_notation`).

    Optional keyword arguments:

    - ``message`` - define a custom message to be used in the raised exception
    - ``fatal`` - if True, will raise :class:`ParseFatalException` to stop parsing immediately;
      otherwise will raise :class:`ParseException`

    """
    msg = message if message is not None else "failed user-defined condition"
    exc_type = ParseFatalException if fatal else ParseException
    fn = _trim_arity(fn)

    @wraps(fn)
    def pa(s, l, t):
        if not bool(fn(s, l, t)):
            raise exc_type(s, l, msg)

    return pa


def _default_start_debug_action(
    instring: str, loc: int, expr: "ParserElement", cache_hit: bool = False
):
    cache_hit_str = "*" if cache_hit else ""
    print(
        (
            "{}Match {} at loc {}({},{})\n  {}\n  {}^".format(
                cache_hit_str,
                expr,
                loc,
                lineno(loc, instring),
                col(loc, instring),
                line(loc, instring),
                " " * (col(loc, instring) - 1),
            )
        )
    )


def _default_success_debug_action(
    instring: str,
    startloc: int,
    endloc: int,
    expr: "ParserElement",
    toks: ParseResults,
    cache_hit: bool = False,
):
    cache_hit_str = "*" if cache_hit else ""
    print("{}Matched {} -> {}".format(cache_hit_str, expr, toks.as_list()))


def _default_exception_debug_action(
    instring: str,
    loc: int,
    expr: "ParserElement",
    exc: Exception,
    cache_hit: bool = False,
):
    cache_hit_str = "*" if cache_hit else ""
    print(
        "{}Match {} failed, {} raised: {}".format(
            cache_hit_str, expr, type(exc).__name__, exc
        )
    )


def null_debug_action(*args):
    """'Do-nothing' debug action, to suppress debugging output during parsing."""


class ParserElement(ABC):
    """Abstract base level parser element class."""

    DEFAULT_WHITE_CHARS: str = " \n\t\r"
    verbose_stacktrace: bool = False
    _literalStringClass: typing.Optional[type] = None

    @staticmethod
    def set_default_whitespace_chars(chars: str) -> None:
        r"""
        Overrides the default whitespace chars

        Example::

            # default whitespace chars are space, <TAB> and newline
            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']

            # change to just treat newline as significant
            ParserElement.set_default_whitespace_chars(" \t")
            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def']
        """
        ParserElement.DEFAULT_WHITE_CHARS = chars

        # update whitespace all parse expressions defined in this module
        for expr in _builtin_exprs:
            if expr.copyDefaultWhiteChars:
                expr.whiteChars = set(chars)

    @staticmethod
    def inline_literals_using(cls: type) -> None:
        """
        Set class to be used for inclusion of string literals into a parser.

        Example::

            # default literal class used is Literal
            integer = Word(nums)
            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")

            date_str.parse_string("1999/12/31")  # -> ['1999', '/', '12', '/', '31']


            # change to Suppress
            ParserElement.inline_literals_using(Suppress)
            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")

            date_str.parse_string("1999/12/31")  # -> ['1999', '12', '31']
        """
        ParserElement._literalStringClass = cls

    class DebugActions(NamedTuple):
        debug_try: typing.Optional[DebugStartAction]
        debug_match: typing.Optional[DebugSuccessAction]
        debug_fail: typing.Optional[DebugExceptionAction]

    def __init__(self, savelist: bool = False):
        self.parseAction: List[ParseAction] = list()
        self.failAction: typing.Optional[ParseFailAction] = None
        self.customName = None
        self._defaultName = None
        self.resultsName = None
        self.saveAsList = savelist
        self.skipWhitespace = True
        self.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS)
        self.copyDefaultWhiteChars = True
        # used when checking for left-recursion
        self.mayReturnEmpty = False
        self.keepTabs = False
        self.ignoreExprs: List["ParserElement"] = list()
        self.debug = False
        self.streamlined = False
        # optimize exception handling for subclasses that don't advance parse index
        self.mayIndexError = True
        self.errmsg = ""
        # mark results names as modal (report only last) or cumulative (list all)
        self.modalResults = True
        # custom debug actions
        self.debugActions = self.DebugActions(None, None, None)
        # avoid redundant calls to preParse
        self.callPreparse = True
        self.callDuringTry = False
        self.suppress_warnings_: List[Diagnostics] = []

    def suppress_warning(self, warning_type: Diagnostics) -> "ParserElement":
        """
        Suppress warnings emitted for a particular diagnostic on this expression.

        Example::

            base = pp.Forward()
            base.suppress_warning(Diagnostics.warn_on_parse_using_empty_Forward)

            # statement would normally raise a warning, but is now suppressed
            print(base.parseString("x"))

        """
        self.suppress_warnings_.append(warning_type)
        return self

    def copy(self) -> "ParserElement":
        """
        Make a copy of this :class:`ParserElement`.  Useful for defining
        different parse actions for the same parsing pattern, using copies of
        the original parse element.

        Example::

            integer = Word(nums).set_parse_action(lambda toks: int(toks[0]))
            integerK = integer.copy().add_parse_action(lambda toks: toks[0] * 1024) + Suppress("K")
            integerM = integer.copy().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")

            print((integerK | integerM | integer)[1, ...].parse_string("5K 100 640K 256M"))

        prints::

            [5120, 100, 655360, 268435456]

        Equivalent form of ``expr.copy()`` is just ``expr()``::

            integerM = integer().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")
        """
        cpy = copy.copy(self)
        cpy.parseAction = self.parseAction[:]
        cpy.ignoreExprs = self.ignoreExprs[:]
        if self.copyDefaultWhiteChars:
            cpy.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS)
        return cpy

    def set_results_name(
        self, name: str, list_all_matches: bool = False, *, listAllMatches: bool = False
    ) -> "ParserElement":
        """
        Define name for referencing matching tokens as a nested attribute
        of the returned parse results.

        Normally, results names are assigned as you would assign keys in a dict:
        any existing value is overwritten by later values. If it is necessary to
        keep all values captured for a particular results name, call ``set_results_name``
        with ``list_all_matches`` = True.

        NOTE: ``set_results_name`` returns a *copy* of the original :class:`ParserElement` object;
        this is so that the client can define a basic element, such as an
        integer, and reference it in multiple places with different names.

        You can also set results names using the abbreviated syntax,
        ``expr("name")`` in place of ``expr.set_results_name("name")``
        - see :class:`__call__`. If ``list_all_matches`` is required, use
        ``expr("name*")``.

        Example::

            date_str = (integer.set_results_name("year") + '/'
                        + integer.set_results_name("month") + '/'
                        + integer.set_results_name("day"))

            # equivalent form:
            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
        """
        listAllMatches = listAllMatches or list_all_matches
        return self._setResultsName(name, listAllMatches)

    def _setResultsName(self, name, listAllMatches=False):
        if name is None:
            return self
        newself = self.copy()
        if name.endswith("*"):
            name = name[:-1]
            listAllMatches = True
        newself.resultsName = name
        newself.modalResults = not listAllMatches
        return newself

    def set_break(self, break_flag: bool = True) -> "ParserElement":
        """
        Method to invoke the Python pdb debugger when this element is
        about to be parsed. Set ``break_flag`` to ``True`` to enable, ``False`` to
        disable.
        """
        if break_flag:
            _parseMethod = self._parse

            def breaker(instring, loc, doActions=True, callPreParse=True):
                import pdb

                # this call to pdb.set_trace() is intentional, not a checkin error
                pdb.set_trace()
                return _parseMethod(instring, loc, doActions, callPreParse)

            breaker._originalParseMethod = _parseMethod
            self._parse = breaker
        else:
            if hasattr(self._parse, "_originalParseMethod"):
                self._parse = self._parse._originalParseMethod
        return self

    def set_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement":
        """
        Define one or more actions to perform when successfully matching parse element definition.

        Parse actions can be called to perform data conversions, do extra validation,
        update external data structures, or enhance or replace the parsed tokens.
        Each parse action ``fn`` is a callable method with 0-3 arguments, called as
        ``fn(s, loc, toks)`` , ``fn(loc, toks)`` , ``fn(toks)`` , or just ``fn()`` , where:

        - s   = the original string being parsed (see note below)
        - loc = the location of the matching substring
        - toks = a list of the matched tokens, packaged as a :class:`ParseResults` object

        The parsed tokens are passed to the parse action as ParseResults. They can be
        modified in place using list-style append, extend, and pop operations to update
        the parsed list elements; and with dictionary-style item set and del operations
        to add, update, or remove any named results. If the tokens are modified in place,
        it is not necessary to return them with a return statement.

        Parse actions can also completely replace the given tokens, with another ``ParseResults``
        object, or with some entirely different object (common for parse actions that perform data
        conversions). A convenient way to build a new parse result is to define the values
        using a dict, and then create the return value using :class:`ParseResults.from_dict`.

        If None is passed as the ``fn`` parse action, all previously added parse actions for this
        expression are cleared.

        Optional keyword arguments:

        - call_during_try = (default= ``False``) indicate if parse action should be run during
          lookaheads and alternate testing. For parse actions that have side effects, it is
          important to only call the parse action once it is determined that it is being
          called as part of a successful parse. For parse actions that perform additional
          validation, then call_during_try should be passed as True, so that the validation
          code is included in the preliminary "try" parses.

        Note: the default parsing behavior is to expand tabs in the input string
        before starting the parsing process.  See :class:`parse_string` for more
        information on parsing strings containing ``<TAB>`` s, and suggested
        methods to maintain a consistent view of the parsed string, the parse
        location, and line and column positions within the parsed string.

        Example::

            # parse dates in the form YYYY/MM/DD

            # use parse action to convert toks from str to int at parse time
            def convert_to_int(toks):
                return int(toks[0])

            # use a parse action to verify that the date is a valid date
            def is_valid_date(instring, loc, toks):
                from datetime import date
                year, month, day = toks[::2]
                try:
                    date(year, month, day)
                except ValueError:
                    raise ParseException(instring, loc, "invalid date given")

            integer = Word(nums)
            date_str = integer + '/' + integer + '/' + integer

            # add parse actions
            integer.set_parse_action(convert_to_int)
            date_str.set_parse_action(is_valid_date)

            # note that integer fields are now ints, not strings
            date_str.run_tests('''
                # successful parse - note that integer fields were converted to ints
                1999/12/31

                # fail - invalid date
                1999/13/31
                ''')
        """
        if list(fns) == [None]:
            self.parseAction = []
        else:
            if not all(callable(fn) for fn in fns):
                raise TypeError("parse actions must be callable")
            self.parseAction = [_trim_arity(fn) for fn in fns]
            self.callDuringTry = kwargs.get(
                "call_during_try", kwargs.get("callDuringTry", False)
            )
        return self

    def add_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement":
        """
        Add one or more parse actions to expression's list of parse actions. See :class:`set_parse_action`.

        See examples in :class:`copy`.
        """
        self.parseAction += [_trim_arity(fn) for fn in fns]
        self.callDuringTry = self.callDuringTry or kwargs.get(
            "call_during_try", kwargs.get("callDuringTry", False)
        )
        return self

    def add_condition(self, *fns: ParseCondition, **kwargs) -> "ParserElement":
        """Add a boolean predicate function to expression's list of parse actions. See
        :class:`set_parse_action` for function call signatures. Unlike ``set_parse_action``,
        functions passed to ``add_condition`` need to return boolean success/fail of the condition.

        Optional keyword arguments:

        - message = define a custom message to be used in the raised exception
        - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise
          ParseException
        - call_during_try = boolean to indicate if this method should be called during internal tryParse calls,
          default=False

        Example::

            integer = Word(nums).set_parse_action(lambda toks: int(toks[0]))
            year_int = integer.copy()
            year_int.add_condition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later")
            date_str = year_int + '/' + integer + '/' + integer

            result = date_str.parse_string("1999/12/31")  # -> Exception: Only support years 2000 and later (at char 0),
                                                                         (line:1, col:1)
        """
        for fn in fns:
            self.parseAction.append(
                condition_as_parse_action(
                    fn, message=kwargs.get("message"), fatal=kwargs.get("fatal", False)
                )
            )

        self.callDuringTry = self.callDuringTry or kwargs.get(
            "call_during_try", kwargs.get("callDuringTry", False)
        )
        return self

    def set_fail_action(self, fn: ParseFailAction) -> "ParserElement":
        """
        Define action to perform if parsing fails at this expression.
        Fail acton fn is a callable function that takes the arguments
        ``fn(s, loc, expr, err)`` where:

        - s = string being parsed
        - loc = location where expression match was attempted and failed
        - expr = the parse expression that failed
        - err = the exception thrown

        The function returns no value.  It may throw :class:`ParseFatalException`
        if it is desired to stop parsing immediately."""
        self.failAction = fn
        return self

    def _skipIgnorables(self, instring, loc):
        exprsFound = True
        while exprsFound:
            exprsFound = False
            for e in self.ignoreExprs:
                try:
                    while 1:
                        loc, dummy = e._parse(instring, loc)
                        exprsFound = True
                except ParseException:
                    pass
        return loc

    def preParse(self, instring, loc):
        if self.ignoreExprs:
            loc = self._skipIgnorables(instring, loc)

        if self.skipWhitespace:
            instrlen = len(instring)
            white_chars = self.whiteChars
            while loc < instrlen and instring[loc] in white_chars:
                loc += 1

        return loc

    def parseImpl(self, instring, loc, doActions=True):
        return loc, []

    def postParse(self, instring, loc, tokenlist):
        return tokenlist

    # @profile
    def _parseNoCache(
        self, instring, loc, doActions=True, callPreParse=True
    ) -> Tuple[int, ParseResults]:
        TRY, MATCH, FAIL = 0, 1, 2
        debugging = self.debug  # and doActions)
        len_instring = len(instring)

        if debugging or self.failAction:
            # print("Match {} at loc {}({}, {})".format(self, loc, lineno(loc, instring), col(loc, instring)))
            try:
                if callPreParse and self.callPreparse:
                    pre_loc = self.preParse(instring, loc)
                else:
                    pre_loc = loc
                tokens_start = pre_loc
                if self.debugActions.debug_try:
                    self.debugActions.debug_try(instring, tokens_start, self, False)
                if self.mayIndexError or pre_loc >= len_instring:
                    try:
                        loc, tokens = self.parseImpl(instring, pre_loc, doActions)
                    except IndexError:
                        raise ParseException(instring, len_instring, self.errmsg, self)
                else:
                    loc, tokens = self.parseImpl(instring, pre_loc, doActions)
            except Exception as err:
                # print("Exception raised:", err)
                if self.debugActions.debug_fail:
                    self.debugActions.debug_fail(
                        instring, tokens_start, self, err, False
                    )
                if self.failAction:
                    self.failAction(instring, tokens_start, self, err)
                raise
        else:
            if callPreParse and self.callPreparse:
                pre_loc = self.preParse(instring, loc)
            else:
                pre_loc = loc
            tokens_start = pre_loc
            if self.mayIndexError or pre_loc >= len_instring:
                try:
                    loc, tokens = self.parseImpl(instring, pre_loc, doActions)
                except IndexError:
                    raise ParseException(instring, len_instring, self.errmsg, self)
            else:
                loc, tokens = self.parseImpl(instring, pre_loc, doActions)

        tokens = self.postParse(instring, loc, tokens)

        ret_tokens = ParseResults(
            tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults
        )
        if self.parseAction and (doActions or self.callDuringTry):
            if debugging:
                try:
                    for fn in self.parseAction:
                        try:
                            tokens = fn(instring, tokens_start, ret_tokens)
                        except IndexError as parse_action_exc:
                            exc = ParseException("exception raised in parse action")
                            raise exc from parse_action_exc

                        if tokens is not None and tokens is not ret_tokens:
                            ret_tokens = ParseResults(
                                tokens,
                                self.resultsName,
                                asList=self.saveAsList
                                and isinstance(tokens, (ParseResults, list)),
                                modal=self.modalResults,
                            )
                except Exception as err:
                    # print "Exception raised in user parse action:", err
                    if self.debugActions.debug_fail:
                        self.debugActions.debug_fail(
                            instring, tokens_start, self, err, False
                        )
                    raise
            else:
                for fn in self.parseAction:
                    try:
                        tokens = fn(instring, tokens_start, ret_tokens)
                    except IndexError as parse_action_exc:
                        exc = ParseException("exception raised in parse action")
                        raise exc from parse_action_exc

                    if tokens is not None and tokens is not ret_tokens:
                        ret_tokens = ParseResults(
                            tokens,
                            self.resultsName,
                            asList=self.saveAsList
                            and isinstance(tokens, (ParseResults, list)),
                            modal=self.modalResults,
                        )
        if debugging:
            # print("Matched", self, "->", ret_tokens.as_list())
            if self.debugActions.debug_match:
                self.debugActions.debug_match(
                    instring, tokens_start, loc, self, ret_tokens, False
                )

        return loc, ret_tokens

    def try_parse(self, instring: str, loc: int, raise_fatal: bool = False) -> int:
        try:
            return self._parse(instring, loc, doActions=False)[0]
        except ParseFatalException:
            if raise_fatal:
                raise
            raise ParseException(instring, loc, self.errmsg, self)

    def can_parse_next(self, instring: str, loc: int) -> bool:
        try:
            self.try_parse(instring, loc)
        except (ParseException, IndexError):
            return False
        else:
            return True

    # cache for left-recursion in Forward references
    recursion_lock = RLock()
    recursion_memos: typing.Dict[
        Tuple[int, "Forward", bool], Tuple[int, Union[ParseResults, Exception]]
    ] = {}

    # argument cache for optimizing repeated calls when backtracking through recursive expressions
    packrat_cache = (
        {}
    )  # this is set later by enabled_packrat(); this is here so that reset_cache() doesn't fail
    packrat_cache_lock = RLock()
    packrat_cache_stats = [0, 0]

    # this method gets repeatedly called during backtracking with the same arguments -
    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
    def _parseCache(
        self, instring, loc, doActions=True, callPreParse=True
    ) -> Tuple[int, ParseResults]:
        HIT, MISS = 0, 1
        TRY, MATCH, FAIL = 0, 1, 2
        lookup = (self, instring, loc, callPreParse, doActions)
        with ParserElement.packrat_cache_lock:
            cache = ParserElement.packrat_cache
            value = cache.get(lookup)
            if value is cache.not_in_cache:
                ParserElement.packrat_cache_stats[MISS] += 1
                try:
                    value = self._parseNoCache(instring, loc, doActions, callPreParse)
                except ParseBaseException as pe:
                    # cache a copy of the exception, without the traceback
                    cache.set(lookup, pe.__class__(*pe.args))
                    raise
                else:
                    cache.set(lookup, (value[0], value[1].copy(), loc))
                    return value
            else:
                ParserElement.packrat_cache_stats[HIT] += 1
                if self.debug and self.debugActions.debug_try:
                    try:
                        self.debugActions.debug_try(instring, loc, self, cache_hit=True)
                    except TypeError:
                        pass
                if isinstance(value, Exception):
                    if self.debug and self.debugActions.debug_fail:
                        try:
                            self.debugActions.debug_fail(
                                instring, loc, self, value, cache_hit=True
                            )
                        except TypeError:
                            pass
                    raise value

                loc_, result, endloc = value[0], value[1].copy(), value[2]
                if self.debug and self.debugActions.debug_match:
                    try:
                        self.debugActions.debug_match(
                            instring, loc_, endloc, self, result, cache_hit=True
                        )
                    except TypeError:
                        pass

                return loc_, result

    _parse = _parseNoCache

    @staticmethod
    def reset_cache() -> None:
        ParserElement.packrat_cache.clear()
        ParserElement.packrat_cache_stats[:] = [0] * len(
            ParserElement.packrat_cache_stats
        )
        ParserElement.recursion_memos.clear()

    _packratEnabled = False
    _left_recursion_enabled = False

    @staticmethod
    def disable_memoization() -> None:
        """
        Disables active Packrat or Left Recursion parsing and their memoization

        This method also works if neither Packrat nor Left Recursion are enabled.
        This makes it safe to call before activating Packrat nor Left Recursion
        to clear any previous settings.
        """
        ParserElement.reset_cache()
        ParserElement._left_recursion_enabled = False
        ParserElement._packratEnabled = False
        ParserElement._parse = ParserElement._parseNoCache

    @staticmethod
    def enable_left_recursion(
        cache_size_limit: typing.Optional[int] = None, *, force=False
    ) -> None:
        """
        Enables "bounded recursion" parsing, which allows for both direct and indirect
        left-recursion. During parsing, left-recursive :class:`Forward` elements are
        repeatedly matched with a fixed recursion depth that is gradually increased
        until finding the longest match.

        Example::

            import pyparsing as pp
            pp.ParserElement.enable_left_recursion()

            E = pp.Forward("E")
            num = pp.Word(pp.nums)
            # match `num`, or `num '+' num`, or `num '+' num '+' num`, ...
            E <<= E + '+' - num | num

            print(E.parse_string("1+2+3"))

        Recursion search naturally memoizes matches of ``Forward`` elements and may
        thus skip reevaluation of parse actions during backtracking. This may break
        programs with parse actions which rely on strict ordering of side-effects.

        Parameters:

        - cache_size_limit - (default=``None``) - memoize at most this many
          ``Forward`` elements during matching; if ``None`` (the default),
          memoize all ``Forward`` elements.

        Bounded Recursion parsing works similar but not identical to Packrat parsing,
        thus the two cannot be used together. Use ``force=True`` to disable any
        previous, conflicting settings.
        """
        if force:
            ParserElement.disable_memoization()
        elif ParserElement._packratEnabled:
            raise RuntimeError("Packrat and Bounded Recursion are not compatible")
        if cache_size_limit is None:
            ParserElement.recursion_memos = _UnboundedMemo()
        elif cache_size_limit > 0:
            ParserElement.recursion_memos = _LRUMemo(capacity=cache_size_limit)
        else:
            raise NotImplementedError("Memo size of %s" % cache_size_limit)
        ParserElement._left_recursion_enabled = True

    @staticmethod
    def enable_packrat(cache_size_limit: int = 128, *, force: bool = False) -> None:
        """
        Enables "packrat" parsing, which adds memoizing to the parsing logic.
        Repeated parse attempts at the same string location (which happens
        often in many complex grammars) can immediately return a cached value,
        instead of re-executing parsing/validating code.  Memoizing is done of
        both valid results and parsing exceptions.

        Parameters:

        - cache_size_limit - (default= ``128``) - if an integer value is provided
          will limit the size of the packrat cache; if None is passed, then
          the cache size will be unbounded; if 0 is passed, the cache will
          be effectively disabled.

        This speedup may break existing programs that use parse actions that
        have side-effects.  For this reason, packrat parsing is disabled when
        you first import pyparsing.  To activate the packrat feature, your
        program must call the class method :class:`ParserElement.enable_packrat`.
        For best results, call ``enable_packrat()`` immediately after
        importing pyparsing.

        Example::

            import pyparsing
            pyparsing.ParserElement.enable_packrat()

        Packrat parsing works similar but not identical to Bounded Recursion parsing,
        thus the two cannot be used together. Use ``force=True`` to disable any
        previous, conflicting settings.
        """
        if force:
            ParserElement.disable_memoization()
        elif ParserElement._left_recursion_enabled:
            raise RuntimeError("Packrat and Bounded Recursion are not compatible")
        if not ParserElement._packratEnabled:
            ParserElement._packratEnabled = True
            if cache_size_limit is None:
                ParserElement.packrat_cache = _UnboundedCache()
            else:
                ParserElement.packrat_cache = _FifoCache(cache_size_limit)
            ParserElement._parse = ParserElement._parseCache

    def parse_string(
        self, instring: str, parse_all: bool = False, *, parseAll: bool = False
    ) -> ParseResults:
        """
        Parse a string with respect to the parser definition. This function is intended as the primary interface to the
        client code.

        :param instring: The input string to be parsed.
        :param parse_all: If set, the entire input string must match the grammar.
        :param parseAll: retained for pre-PEP8 compatibility, will be removed in a future release.
        :raises ParseException: Raised if ``parse_all`` is set and the input string does not match the whole grammar.
        :returns: the parsed data as a :class:`ParseResults` object, which may be accessed as a `list`, a `dict`, or
          an object with attributes if the given parser includes results names.

        If the input string is required to match the entire grammar, ``parse_all`` flag must be set to ``True``. This
        is also equivalent to ending the grammar with :class:`StringEnd`().

        To report proper column numbers, ``parse_string`` operates on a copy of the input string where all tabs are
        converted to spaces (8 spaces per tab, as per the default in ``string.expandtabs``). If the input string
        contains tabs and the grammar uses parse actions that use the ``loc`` argument to index into the string
        being parsed, one can ensure a consistent view of the input string by doing one of the following:

        - calling ``parse_with_tabs`` on your grammar before calling ``parse_string`` (see :class:`parse_with_tabs`),
        - define your parse action using the full ``(s,loc,toks)`` signature, and reference the input string using the
          parse action's ``s`` argument, or
        - explicitly expand the tabs in your input string before calling ``parse_string``.

        Examples:

        By default, partial matches are OK.

        >>> res = Word('a').parse_string('aaaaabaaa')
        >>> print(res)
        ['aaaaa']

        The parsing behavior varies by the inheriting class of this abstract class. Please refer to the children
        directly to see more examples.

        It raises an exception if parse_all flag is set and instring does not match the whole grammar.

        >>> res = Word('a').parse_string('aaaaabaaa', parse_all=True)
        Traceback (most recent call last):
        ...
        pyparsing.ParseException: Expected end of text, found 'b'  (at char 5), (line:1, col:6)
        """
        parseAll = parse_all or parseAll

        ParserElement.reset_cache()
        if not self.streamlined:
            self.streamline()
        for e in self.ignoreExprs:
            e.streamline()
        if not self.keepTabs:
            instring = instring.expandtabs()
        try:
            loc, tokens = self._parse(instring, 0)
            if parseAll:
                loc = self.preParse(instring, loc)
                se = Empty() + StringEnd()
                se._parse(instring, loc)
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clearing out pyparsing internal stack trace
                raise exc.with_traceback(None)
        else:
            return tokens

    def scan_string(
        self,
        instring: str,
        max_matches: int = _MAX_INT,
        overlap: bool = False,
        *,
        debug: bool = False,
        maxMatches: int = _MAX_INT,
    ) -> Generator[Tuple[ParseResults, int, int], None, None]:
        """
        Scan the input string for expression matches.  Each match will return the
        matching tokens, start location, and end location.  May be called with optional
        ``max_matches`` argument, to clip scanning after 'n' matches are found.  If
        ``overlap`` is specified, then overlapping matches will be reported.

        Note that the start and end locations are reported relative to the string
        being parsed.  See :class:`parse_string` for more information on parsing
        strings with embedded tabs.

        Example::

            source = "sldjf123lsdjjkf345sldkjf879lkjsfd987"
            print(source)
            for tokens, start, end in Word(alphas).scan_string(source):
                print(' '*start + '^'*(end-start))
                print(' '*start + tokens[0])

        prints::

            sldjf123lsdjjkf345sldkjf879lkjsfd987
            ^^^^^
            sldjf
                    ^^^^^^^
                    lsdjjkf
                              ^^^^^^
                              sldkjf
                                       ^^^^^^
                                       lkjsfd
        """
        maxMatches = min(maxMatches, max_matches)
        if not self.streamlined:
            self.streamline()
        for e in self.ignoreExprs:
            e.streamline()

        if not self.keepTabs:
            instring = str(instring).expandtabs()
        instrlen = len(instring)
        loc = 0
        preparseFn = self.preParse
        parseFn = self._parse
        ParserElement.resetCache()
        matches = 0
        try:
            while loc <= instrlen and matches < maxMatches:
                try:
                    preloc = preparseFn(instring, loc)
                    nextLoc, tokens = parseFn(instring, preloc, callPreParse=False)
                except ParseException:
                    loc = preloc + 1
                else:
                    if nextLoc > loc:
                        matches += 1
                        if debug:
                            print(
                                {
                                    "tokens": tokens.asList(),
                                    "start": preloc,
                                    "end": nextLoc,
                                }
                            )
                        yield tokens, preloc, nextLoc
                        if overlap:
                            nextloc = preparseFn(instring, loc)
                            if nextloc > loc:
                                loc = nextLoc
                            else:
                                loc += 1
                        else:
                            loc = nextLoc
                    else:
                        loc = preloc + 1
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def transform_string(self, instring: str, *, debug: bool = False) -> str:
        """
        Extension to :class:`scan_string`, to modify matching text with modified tokens that may
        be returned from a parse action.  To use ``transform_string``, define a grammar and
        attach a parse action to it that modifies the returned token list.
        Invoking ``transform_string()`` on a target string will then scan for matches,
        and replace the matched text patterns according to the logic in the parse
        action.  ``transform_string()`` returns the resulting transformed string.

        Example::

            wd = Word(alphas)
            wd.set_parse_action(lambda toks: toks[0].title())

            print(wd.transform_string("now is the winter of our discontent made glorious summer by this sun of york."))

        prints::

            Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York.
        """
        out: List[str] = []
        lastE = 0
        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
        # keep string locs straight between transform_string and scan_string
        self.keepTabs = True
        try:
            for t, s, e in self.scan_string(instring, debug=debug):
                out.append(instring[lastE:s])
                if t:
                    if isinstance(t, ParseResults):
                        out += t.as_list()
                    elif isinstance(t, Iterable) and not isinstance(t, str_type):
                        out.extend(t)
                    else:
                        out.append(t)
                lastE = e
            out.append(instring[lastE:])
            out = [o for o in out if o]
            return "".join([str(s) for s in _flatten(out)])
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def search_string(
        self,
        instring: str,
        max_matches: int = _MAX_INT,
        *,
        debug: bool = False,
        maxMatches: int = _MAX_INT,
    ) -> ParseResults:
        """
        Another extension to :class:`scan_string`, simplifying the access to the tokens found
        to match the given parse expression.  May be called with optional
        ``max_matches`` argument, to clip searching after 'n' matches are found.

        Example::

            # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters
            cap_word = Word(alphas.upper(), alphas.lower())

            print(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity"))

            # the sum() builtin can be used to merge results into a single ParseResults object
            print(sum(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity")))

        prints::

            [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']]
            ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity']
        """
        maxMatches = min(maxMatches, max_matches)
        try:
            return ParseResults(
                [t for t, s, e in self.scan_string(instring, maxMatches, debug=debug)]
            )
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def split(
        self,
        instring: str,
        maxsplit: int = _MAX_INT,
        include_separators: bool = False,
        *,
        includeSeparators=False,
    ) -> Generator[str, None, None]:
        """
        Generator method to split a string using the given expression as a separator.
        May be called with optional ``maxsplit`` argument, to limit the number of splits;
        and the optional ``include_separators`` argument (default= ``False``), if the separating
        matching text should be included in the split results.

        Example::

            punc = one_of(list(".,;:/-!?"))
            print(list(punc.split("This, this?, this sentence, is badly punctuated!")))

        prints::

            ['This', ' this', '', ' this sentence', ' is badly punctuated', '']
        """
        includeSeparators = includeSeparators or include_separators
        last = 0
        for t, s, e in self.scan_string(instring, max_matches=maxsplit):
            yield instring[last:s]
            if includeSeparators:
                yield t[0]
            last = e
        yield instring[last:]

    def __add__(self, other) -> "ParserElement":
        """
        Implementation of ``+`` operator - returns :class:`And`. Adding strings to a :class:`ParserElement`
        converts them to :class:`Literal`s by default.

        Example::

            greet = Word(alphas) + "," + Word(alphas) + "!"
            hello = "Hello, World!"
            print(hello, "->", greet.parse_string(hello))

        prints::

            Hello, World! -> ['Hello', ',', 'World', '!']

        ``...`` may be used as a parse expression as a short form of :class:`SkipTo`.

            Literal('start') + ... + Literal('end')

        is equivalent to:

            Literal('start') + SkipTo('end')("_skipped*") + Literal('end')

        Note that the skipped text is returned with '_skipped' as a results name,
        and to support having multiple skips in the same parser, the value returned is
        a list of all skipped text.
        """
        if other is Ellipsis:
            return _PendingSkip(self)

        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return And([self, other])

    def __radd__(self, other) -> "ParserElement":
        """
        Implementation of ``+`` operator when left operand is not a :class:`ParserElement`
        """
        if other is Ellipsis:
            return SkipTo(self)("_skipped*") + self

        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other + self

    def __sub__(self, other) -> "ParserElement":
        """
        Implementation of ``-`` operator, returns :class:`And` with error stop
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return self + And._ErrorStop() + other

    def __rsub__(self, other) -> "ParserElement":
        """
        Implementation of ``-`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other - self

    def __mul__(self, other) -> "ParserElement":
        """
        Implementation of ``*`` operator, allows use of ``expr * 3`` in place of
        ``expr + expr + expr``.  Expressions may also be multiplied by a 2-integer
        tuple, similar to ``{min, max}`` multipliers in regular expressions.  Tuples
        may also include ``None`` as in:
        - ``expr*(n, None)`` or ``expr*(n, )`` is equivalent
             to ``expr*n + ZeroOrMore(expr)``
             (read as "at least n instances of ``expr``")
        - ``expr*(None, n)`` is equivalent to ``expr*(0, n)``
             (read as "0 to n instances of ``expr``")
        - ``expr*(None, None)`` is equivalent to ``ZeroOrMore(expr)``
        - ``expr*(1, None)`` is equivalent to ``OneOrMore(expr)``

        Note that ``expr*(None, n)`` does not raise an exception if
        more than n exprs exist in the input stream; that is,
        ``expr*(None, n)`` does not enforce a maximum number of expr
        occurrences.  If this behavior is desired, then write
        ``expr*(None, n) + ~expr``
        """
        if other is Ellipsis:
            other = (0, None)
        elif isinstance(other, tuple) and other[:1] == (Ellipsis,):
            other = ((0,) + other[1:] + (None,))[:2]

        if isinstance(other, int):
            minElements, optElements = other, 0
        elif isinstance(other, tuple):
            other = tuple(o if o is not Ellipsis else None for o in other)
            other = (other + (None, None))[:2]
            if other[0] is None:
                other = (0, other[1])
            if isinstance(other[0], int) and other[1] is None:
                if other[0] == 0:
                    return ZeroOrMore(self)
                if other[0] == 1:
                    return OneOrMore(self)
                else:
                    return self * other[0] + ZeroOrMore(self)
            elif isinstance(other[0], int) and isinstance(other[1], int):
                minElements, optElements = other
                optElements -= minElements
            else:
                raise TypeError(
                    "cannot multiply ParserElement and ({}) objects".format(
                        ",".join(type(item).__name__ for item in other)
                    )
                )
        else:
            raise TypeError(
                "cannot multiply ParserElement and {} objects".format(
                    type(other).__name__
                )
            )

        if minElements < 0:
            raise ValueError("cannot multiply ParserElement by negative value")
        if optElements < 0:
            raise ValueError(
                "second tuple value must be greater or equal to first tuple value"
            )
        if minElements == optElements == 0:
            return And([])

        if optElements:

            def makeOptionalList(n):
                if n > 1:
                    return Opt(self + makeOptionalList(n - 1))
                else:
                    return Opt(self)

            if minElements:
                if minElements == 1:
                    ret = self + makeOptionalList(optElements)
                else:
                    ret = And([self] * minElements) + makeOptionalList(optElements)
            else:
                ret = makeOptionalList(optElements)
        else:
            if minElements == 1:
                ret = self
            else:
                ret = And([self] * minElements)
        return ret

    def __rmul__(self, other) -> "ParserElement":
        return self.__mul__(other)

    def __or__(self, other) -> "ParserElement":
        """
        Implementation of ``|`` operator - returns :class:`MatchFirst`
        """
        if other is Ellipsis:
            return _PendingSkip(self, must_skip=True)

        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return MatchFirst([self, other])

    def __ror__(self, other) -> "ParserElement":
        """
        Implementation of ``|`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other | self

    def __xor__(self, other) -> "ParserElement":
        """
        Implementation of ``^`` operator - returns :class:`Or`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return Or([self, other])

    def __rxor__(self, other) -> "ParserElement":
        """
        Implementation of ``^`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other ^ self

    def __and__(self, other) -> "ParserElement":
        """
        Implementation of ``&`` operator - returns :class:`Each`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return Each([self, other])

    def __rand__(self, other) -> "ParserElement":
        """
        Implementation of ``&`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other & self

    def __invert__(self) -> "ParserElement":
        """
        Implementation of ``~`` operator - returns :class:`NotAny`
        """
        return NotAny(self)

    # disable __iter__ to override legacy use of sequential access to __getitem__ to
    # iterate over a sequence
    __iter__ = None

    def __getitem__(self, key):
        """
        use ``[]`` indexing notation as a short form for expression repetition:

        - ``expr[n]`` is equivalent to ``expr*n``
        - ``expr[m, n]`` is equivalent to ``expr*(m, n)``
        - ``expr[n, ...]`` or ``expr[n,]`` is equivalent
             to ``expr*n + ZeroOrMore(expr)``
             (read as "at least n instances of ``expr``")
        - ``expr[..., n]`` is equivalent to ``expr*(0, n)``
             (read as "0 to n instances of ``expr``")
        - ``expr[...]`` and ``expr[0, ...]`` are equivalent to ``ZeroOrMore(expr)``
        - ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)``

        ``None`` may be used in place of ``...``.

        Note that ``expr[..., n]`` and ``expr[m, n]``do not raise an exception
        if more than ``n`` ``expr``s exist in the input stream.  If this behavior is
        desired, then write ``expr[..., n] + ~expr``.
        """

        # convert single arg keys to tuples
        try:
            if isinstance(key, str_type):
                key = (key,)
            iter(key)
        except TypeError:
            key = (key, key)

        if len(key) > 2:
            raise TypeError(
                "only 1 or 2 index arguments supported ({}{})".format(
                    key[:5], "... [{}]".format(len(key)) if len(key) > 5 else ""
                )
            )

        # clip to 2 elements
        ret = self * tuple(key[:2])
        return ret

    def __call__(self, name: str = None) -> "ParserElement":
        """
        Shortcut for :class:`set_results_name`, with ``list_all_matches=False``.

        If ``name`` is given with a trailing ``'*'`` character, then ``list_all_matches`` will be
        passed as ``True``.

        If ``name` is omitted, same as calling :class:`copy`.

        Example::

            # these are equivalent
            userdata = Word(alphas).set_results_name("name") + Word(nums + "-").set_results_name("socsecno")
            userdata = Word(alphas)("name") + Word(nums + "-")("socsecno")
        """
        if name is not None:
            return self._setResultsName(name)
        else:
            return self.copy()

    def suppress(self) -> "ParserElement":
        """
        Suppresses the output of this :class:`ParserElement`; useful to keep punctuation from
        cluttering up returned output.
        """
        return Suppress(self)

    def ignore_whitespace(self, recursive: bool = True) -> "ParserElement":
        """
        Enables the skipping of whitespace before matching the characters in the
        :class:`ParserElement`'s defined pattern.

        :param recursive: If ``True`` (the default), also enable whitespace skipping in child elements (if any)
        """
        self.skipWhitespace = True
        return self

    def leave_whitespace(self, recursive: bool = True) -> "ParserElement":
        """
        Disables the skipping of whitespace before matching the characters in the
        :class:`ParserElement`'s defined pattern.  This is normally only used internally by
        the pyparsing module, but may be needed in some whitespace-sensitive grammars.

        :param recursive: If true (the default), also disable whitespace skipping in child elements (if any)
        """
        self.skipWhitespace = False
        return self

    def set_whitespace_chars(
        self, chars: Union[Set[str], str], copy_defaults: bool = False
    ) -> "ParserElement":
        """
        Overrides the default whitespace chars
        """
        self.skipWhitespace = True
        self.whiteChars = set(chars)
        self.copyDefaultWhiteChars = copy_defaults
        return self

    def parse_with_tabs(self) -> "ParserElement":
        """
        Overrides default behavior to expand ``<TAB>`` s to spaces before parsing the input string.
        Must be called before ``parse_string`` when the input grammar contains elements that
        match ``<TAB>`` characters.
        """
        self.keepTabs = True
        return self

    def ignore(self, other: "ParserElement") -> "ParserElement":
        """
        Define expression to be ignored (e.g., comments) while doing pattern
        matching; may be called repeatedly, to define multiple comment or other
        ignorable patterns.

        Example::

            patt = Word(alphas)[1, ...]
            patt.parse_string('ablaj /* comment */ lskjd')
            # -> ['ablaj']

            patt.ignore(c_style_comment)
            patt.parse_string('ablaj /* comment */ lskjd')
            # -> ['ablaj', 'lskjd']
        """
        import typing

        if isinstance(other, str_type):
            other = Suppress(other)

        if isinstance(other, Suppress):
            if other not in self.ignoreExprs:
                self.ignoreExprs.append(other)
        else:
            self.ignoreExprs.append(Suppress(other.copy()))
        return self

    def set_debug_actions(
        self,
        start_action: DebugStartAction,
        success_action: DebugSuccessAction,
        exception_action: DebugExceptionAction,
    ) -> "ParserElement":
        """
        Customize display of debugging messages while doing pattern matching:

        - ``start_action`` - method to be called when an expression is about to be parsed;
          should have the signature ``fn(input_string: str, location: int, expression: ParserElement, cache_hit: bool)``

        - ``success_action`` - method to be called when an expression has successfully parsed;
          should have the signature ``fn(input_string: str, start_location: int, end_location: int, expression: ParserELement, parsed_tokens: ParseResults, cache_hit: bool)``

        - ``exception_action`` - method to be called when expression fails to parse;
          should have the signature ``fn(input_string: str, location: int, expression: ParserElement, exception: Exception, cache_hit: bool)``
        """
        self.debugActions = self.DebugActions(
            start_action or _default_start_debug_action,
            success_action or _default_success_debug_action,
            exception_action or _default_exception_debug_action,
        )
        self.debug = True
        return self

    def set_debug(self, flag: bool = True) -> "ParserElement":
        """
        Enable display of debugging messages while doing pattern matching.
        Set ``flag`` to ``True`` to enable, ``False`` to disable.

        Example::

            wd = Word(alphas).set_name("alphaword")
            integer = Word(nums).set_name("numword")
            term = wd | integer

            # turn on debugging for wd
            wd.set_debug()

            term[1, ...].parse_string("abc 123 xyz 890")

        prints::

            Match alphaword at loc 0(1,1)
            Matched alphaword -> ['abc']
            Match alphaword at loc 3(1,4)
            Exception raised:Expected alphaword (at char 4), (line:1, col:5)
            Match alphaword at loc 7(1,8)
            Matched alphaword -> ['xyz']
            Match alphaword at loc 11(1,12)
            Exception raised:Expected alphaword (at char 12), (line:1, col:13)
            Match alphaword at loc 15(1,16)
            Exception raised:Expected alphaword (at char 15), (line:1, col:16)

        The output shown is that produced by the default debug actions - custom debug actions can be
        specified using :class:`set_debug_actions`. Prior to attempting
        to match the ``wd`` expression, the debugging message ``"Match <exprname> at loc <n>(<line>,<col>)"``
        is shown. Then if the parse succeeds, a ``"Matched"`` message is shown, or an ``"Exception raised"``
        message is shown. Also note the use of :class:`set_name` to assign a human-readable name to the expression,
        which makes debugging and exception messages easier to understand - for instance, the default
        name created for the :class:`Word` expression without calling ``set_name`` is ``"W:(A-Za-z)"``.
        """
        if flag:
            self.set_debug_actions(
                _default_start_debug_action,
                _default_success_debug_action,
                _default_exception_debug_action,
            )
        else:
            self.debug = False
        return self

    @property
    def default_name(self) -> str:
        if self._defaultName is None:
            self._defaultName = self._generateDefaultName()
        return self._defaultName

    @abstractmethod
    def _generateDefaultName(self):
        """
        Child classes must define this method, which defines how the ``default_name`` is set.
        """

    def set_name(self, name: str) -> "ParserElement":
        """
        Define name for this expression, makes debugging and exception messages clearer.
        Example::
            Word(nums).parse_string("ABC")  # -> Exception: Expected W:(0-9) (at char 0), (line:1, col:1)
            Word(nums).set_name("integer").parse_string("ABC")  # -> Exception: Expected integer (at char 0), (line:1, col:1)
        """
        self.customName = name
        self.errmsg = "Expected " + self.name
        if __diag__.enable_debug_on_named_expressions:
            self.set_debug()
        return self

    @property
    def name(self) -> str:
        # This will use a user-defined name if available, but otherwise defaults back to the auto-generated name
        return self.customName if self.customName is not None else self.default_name

    def __str__(self) -> str:
        return self.name

    def __repr__(self) -> str:
        return str(self)

    def streamline(self) -> "ParserElement":
        self.streamlined = True
        self._defaultName = None
        return self

    def recurse(self) -> Sequence["ParserElement"]:
        return []

    def _checkRecursion(self, parseElementList):
        subRecCheckList = parseElementList[:] + [self]
        for e in self.recurse():
            e._checkRecursion(subRecCheckList)

    def validate(self, validateTrace=None) -> None:
        """
        Check defined expressions for valid structure, check for infinite recursive definitions.
        """
        self._checkRecursion([])

    def parse_file(
        self,
        file_or_filename: Union[str, Path, TextIO],
        encoding: str = "utf-8",
        parse_all: bool = False,
        *,
        parseAll: bool = False,
    ) -> ParseResults:
        """
        Execute the parse expression on the given file or filename.
        If a filename is specified (instead of a file object),
        the entire file is opened, read, and closed before parsing.
        """
        parseAll = parseAll or parse_all
        try:
            file_contents = file_or_filename.read()
        except AttributeError:
            with open(file_or_filename, "r", encoding=encoding) as f:
                file_contents = f.read()
        try:
            return self.parse_string(file_contents, parseAll)
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def __eq__(self, other):
        if self is other:
            return True
        elif isinstance(other, str_type):
            return self.matches(other, parse_all=True)
        elif isinstance(other, ParserElement):
            return vars(self) == vars(other)
        return False

    def __hash__(self):
        return id(self)

    def matches(
        self, test_string: str, parse_all: bool = True, *, parseAll: bool = True
    ) -> bool:
        """
        Method for quick testing of a parser against a test string. Good for simple
        inline microtests of sub expressions while building up larger parser.

        Parameters:
        - ``test_string`` - to test against this expression for a match
        - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests

        Example::

            expr = Word(nums)
            assert expr.matches("100")
        """
        parseAll = parseAll and parse_all
        try:
            self.parse_string(str(test_string), parse_all=parseAll)
            return True
        except ParseBaseException:
            return False

    def run_tests(
        self,
        tests: Union[str, List[str]],
        parse_all: bool = True,
        comment: typing.Optional[Union["ParserElement", str]] = "#",
        full_dump: bool = True,
        print_results: bool = True,
        failure_tests: bool = False,
        post_parse: Callable[[str, ParseResults], str] = None,
        file: typing.Optional[TextIO] = None,
        with_line_numbers: bool = False,
        *,
        parseAll: bool = True,
        fullDump: bool = True,
        printResults: bool = True,
        failureTests: bool = False,
        postParse: Callable[[str, ParseResults], str] = None,
    ) -> Tuple[bool, List[Tuple[str, Union[ParseResults, Exception]]]]:
        """
        Execute the parse expression on a series of test strings, showing each
        test, the parsed results or where the parse failed. Quick and easy way to
        run a parse expression against a list of sample strings.

        Parameters:
        - ``tests`` - a list of separate test strings, or a multiline string of test strings
        - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests
        - ``comment`` - (default= ``'#'``) - expression for indicating embedded comments in the test
          string; pass None to disable comment filtering
        - ``full_dump`` - (default= ``True``) - dump results as list followed by results names in nested outline;
          if False, only dump nested list
        - ``print_results`` - (default= ``True``) prints test output to stdout
        - ``failure_tests`` - (default= ``False``) indicates if these tests are expected to fail parsing
        - ``post_parse`` - (default= ``None``) optional callback for successful parse results; called as
          `fn(test_string, parse_results)` and returns a string to be added to the test output
        - ``file`` - (default= ``None``) optional file-like object to which test output will be written;
          if None, will default to ``sys.stdout``
        - ``with_line_numbers`` - default= ``False``) show test strings with line and column numbers

        Returns: a (success, results) tuple, where success indicates that all tests succeeded
        (or failed if ``failure_tests`` is True), and the results contain a list of lines of each
        test's output

        Example::

            number_expr = pyparsing_common.number.copy()

            result = number_expr.run_tests('''
                # unsigned integer
                100
                # negative integer
                -100
                # float with scientific notation
                6.02e23
                # integer with scientific notation
                1e-12
                ''')
            print("Success" if result[0] else "Failed!")

            result = number_expr.run_tests('''
                # stray character
                100Z
                # missing leading digit before '.'
                -.100
                # too many '.'
                3.14.159
                ''', failure_tests=True)
            print("Success" if result[0] else "Failed!")

        prints::

            # unsigned integer
            100
            [100]

            # negative integer
            -100
            [-100]

            # float with scientific notation
            6.02e23
            [6.02e+23]

            # integer with scientific notation
            1e-12
            [1e-12]

            Success

            # stray character
            100Z
               ^
            FAIL: Expected end of text (at char 3), (line:1, col:4)

            # missing leading digit before '.'
            -.100
            ^
            FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1)

            # too many '.'
            3.14.159
                ^
            FAIL: Expected end of text (at char 4), (line:1, col:5)

            Success

        Each test string must be on a single line. If you want to test a string that spans multiple
        lines, create a test like this::

            expr.run_tests(r"this is a test\\n of strings that spans \\n 3 lines")

        (Note that this is a raw string literal, you must include the leading ``'r'``.)
        """
        from .testing import pyparsing_test

        parseAll = parseAll and parse_all
        fullDump = fullDump and full_dump
        printResults = printResults and print_results
        failureTests = failureTests or failure_tests
        postParse = postParse or post_parse
        if isinstance(tests, str_type):
            line_strip = type(tests).strip
            tests = [line_strip(test_line) for test_line in tests.rstrip().splitlines()]
        if isinstance(comment, str_type):
            comment = Literal(comment)
        if file is None:
            file = sys.stdout
        print_ = file.write

        result: Union[ParseResults, Exception]
        allResults = []
        comments = []
        success = True
        NL = Literal(r"\n").add_parse_action(replace_with("\n")).ignore(quoted_string)
        BOM = "\ufeff"
        for t in tests:
            if comment is not None and comment.matches(t, False) or comments and not t:
                comments.append(
                    pyparsing_test.with_line_numbers(t) if with_line_numbers else t
                )
                continue
            if not t:
                continue
            out = [
                "\n" + "\n".join(comments) if comments else "",
                pyparsing_test.with_line_numbers(t) if with_line_numbers else t,
            ]
            comments = []
            try:
                # convert newline marks to actual newlines, and strip leading BOM if present
                t = NL.transform_string(t.lstrip(BOM))
                result = self.parse_string(t, parse_all=parseAll)
            except ParseBaseException as pe:
                fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else ""
                out.append(pe.explain())
                out.append("FAIL: " + str(pe))
                if ParserElement.verbose_stacktrace:
                    out.extend(traceback.format_tb(pe.__traceback__))
                success = success and failureTests
                result = pe
            except Exception as exc:
                out.append("FAIL-EXCEPTION: {}: {}".format(type(exc).__name__, exc))
                if ParserElement.verbose_stacktrace:
                    out.extend(traceback.format_tb(exc.__traceback__))
                success = success and failureTests
                result = exc
            else:
                success = success and not failureTests
                if postParse is not None:
                    try:
                        pp_value = postParse(t, result)
                        if pp_value is not None:
                            if isinstance(pp_value, ParseResults):
                                out.append(pp_value.dump())
                            else:
                                out.append(str(pp_value))
                        else:
                            out.append(result.dump())
                    except Exception as e:
                        out.append(result.dump(full=fullDump))
                        out.append(
                            "{} failed: {}: {}".format(
                                postParse.__name__, type(e).__name__, e
                            )
                        )
                else:
                    out.append(result.dump(full=fullDump))
            out.append("")

            if printResults:
                print_("\n".join(out))

            allResults.append((t, result))

        return success, allResults

    def create_diagram(
        self,
        output_html: Union[TextIO, Path, str],
        vertical: int = 3,
        show_results_names: bool = False,
        show_groups: bool = False,
        **kwargs,
    ) -> None:
        """
        Create a railroad diagram for the parser.

        Parameters:
        - output_html (str or file-like object) - output target for generated
          diagram HTML
        - vertical (int) - threshold for formatting multiple alternatives vertically
          instead of horizontally (default=3)
        - show_results_names - bool flag whether diagram should show annotations for
          defined results names
        - show_groups - bool flag whether groups should be highlighted with an unlabeled surrounding box
        Additional diagram-formatting keyword arguments can also be included;
        see railroad.Diagram class.
        """

        try:
            from .diagram import to_railroad, railroad_to_html
        except ImportError as ie:
            raise Exception(
                "must ``pip install pyparsing[diagrams]`` to generate parser railroad diagrams"
            ) from ie

        self.streamline()

        railroad = to_railroad(
            self,
            vertical=vertical,
            show_results_names=show_results_names,
            show_groups=show_groups,
            diagram_kwargs=kwargs,
        )
        if isinstance(output_html, (str, Path)):
            with open(output_html, "w", encoding="utf-8") as diag_file:
                diag_file.write(railroad_to_html(railroad))
        else:
            # we were passed a file-like object, just write to it
            output_html.write(railroad_to_html(railroad))

    setDefaultWhitespaceChars = set_default_whitespace_chars
    inlineLiteralsUsing = inline_literals_using
    setResultsName = set_results_name
    setBreak = set_break
    setParseAction = set_parse_action
    addParseAction = add_parse_action
    addCondition = add_condition
    setFailAction = set_fail_action
    tryParse = try_parse
    canParseNext = can_parse_next
    resetCache = reset_cache
    enableLeftRecursion = enable_left_recursion
    enablePackrat = enable_packrat
    parseString = parse_string
    scanString = scan_string
    searchString = search_string
    transformString = transform_string
    setWhitespaceChars = set_whitespace_chars
    parseWithTabs = parse_with_tabs
    setDebugActions = set_debug_actions
    setDebug = set_debug
    defaultName = default_name
    setName = set_name
    parseFile = parse_file
    runTests = run_tests
    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class _PendingSkip(ParserElement):
    # internal placeholder class to hold a place were '...' is added to a parser element,
    # once another ParserElement is added, this placeholder will be replaced with a SkipTo
    def __init__(self, expr: ParserElement, must_skip: bool = False):
        super().__init__()
        self.anchor = expr
        self.must_skip = must_skip

    def _generateDefaultName(self):
        return str(self.anchor + Empty()).replace("Empty", "...")

    def __add__(self, other) -> "ParserElement":
        skipper = SkipTo(other).set_name("...")("_skipped*")
        if self.must_skip:

            def must_skip(t):
                if not t._skipped or t._skipped.as_list() == [""]:
                    del t[0]
                    t.pop("_skipped", None)

            def show_skip(t):
                if t._skipped.as_list()[-1:] == [""]:
                    t.pop("_skipped")
                    t["_skipped"] = "missing <" + repr(self.anchor) + ">"

            return (
                self.anchor + skipper().add_parse_action(must_skip)
                | skipper().add_parse_action(show_skip)
            ) + other

        return self.anchor + skipper + other

    def __repr__(self):
        return self.defaultName

    def parseImpl(self, *args):
        raise Exception(
            "use of `...` expression without following SkipTo target expression"
        )


class Token(ParserElement):
    """Abstract :class:`ParserElement` subclass, for defining atomic
    matching patterns.
    """

    def __init__(self):
        super().__init__(savelist=False)

    def _generateDefaultName(self):
        return type(self).__name__


class Empty(Token):
    """
    An empty token, will always match.
    """

    def __init__(self):
        super().__init__()
        self.mayReturnEmpty = True
        self.mayIndexError = False


class NoMatch(Token):
    """
    A token that will never match.
    """

    def __init__(self):
        super().__init__()
        self.mayReturnEmpty = True
        self.mayIndexError = False
        self.errmsg = "Unmatchable token"

    def parseImpl(self, instring, loc, doActions=True):
        raise ParseException(instring, loc, self.errmsg, self)


class Literal(Token):
    """
    Token to exactly match a specified string.

    Example::

        Literal('blah').parse_string('blah')  # -> ['blah']
        Literal('blah').parse_string('blahfooblah')  # -> ['blah']
        Literal('blah').parse_string('bla')  # -> Exception: Expected "blah"

    For case-insensitive matching, use :class:`CaselessLiteral`.

    For keyword matching (force word break before and after the matched string),
    use :class:`Keyword` or :class:`CaselessKeyword`.
    """

    def __init__(self, match_string: str = "", *, matchString: str = ""):
        super().__init__()
        match_string = matchString or match_string
        self.match = match_string
        self.matchLen = len(match_string)
        try:
            self.firstMatchChar = match_string[0]
        except IndexError:
            raise ValueError("null string passed to Literal; use Empty() instead")
        self.errmsg = "Expected " + self.name
        self.mayReturnEmpty = False
        self.mayIndexError = False

        # Performance tuning: modify __class__ to select
        # a parseImpl optimized for single-character check
        if self.matchLen == 1 and type(self) is Literal:
            self.__class__ = _SingleCharLiteral

    def _generateDefaultName(self):
        return repr(self.match)

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] == self.firstMatchChar and instring.startswith(
            self.match, loc
        ):
            return loc + self.matchLen, self.match
        raise ParseException(instring, loc, self.errmsg, self)


class _SingleCharLiteral(Literal):
    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] == self.firstMatchChar:
            return loc + 1, self.match
        raise ParseException(instring, loc, self.errmsg, self)


ParserElement._literalStringClass = Literal


class Keyword(Token):
    """
    Token to exactly match a specified string as a keyword, that is,
    it must be immediately followed by a non-keyword character.  Compare
    with :class:`Literal`:

    - ``Literal("if")`` will match the leading ``'if'`` in
      ``'ifAndOnlyIf'``.
    - ``Keyword("if")`` will not; it will only match the leading
      ``'if'`` in ``'if x=1'``, or ``'if(y==2)'``

    Accepts two optional constructor arguments in addition to the
    keyword string:

    - ``identChars`` is a string of characters that would be valid
      identifier characters, defaulting to all alphanumerics + "_" and
      "$"
    - ``caseless`` allows case-insensitive matching, default is ``False``.

    Example::

        Keyword("start").parse_string("start")  # -> ['start']
        Keyword("start").parse_string("starting")  # -> Exception

    For case-insensitive matching, use :class:`CaselessKeyword`.
    """

    DEFAULT_KEYWORD_CHARS = alphanums + "_$"

    def __init__(
        self,
        match_string: str = "",
        ident_chars: typing.Optional[str] = None,
        caseless: bool = False,
        *,
        matchString: str = "",
        identChars: typing.Optional[str] = None,
    ):
        super().__init__()
        identChars = identChars or ident_chars
        if identChars is None:
            identChars = Keyword.DEFAULT_KEYWORD_CHARS
        match_string = matchString or match_string
        self.match = match_string
        self.matchLen = len(match_string)
        try:
            self.firstMatchChar = match_string[0]
        except IndexError:
            raise ValueError("null string passed to Keyword; use Empty() instead")
        self.errmsg = "Expected {} {}".format(type(self).__name__, self.name)
        self.mayReturnEmpty = False
        self.mayIndexError = False
        self.caseless = caseless
        if caseless:
            self.caselessmatch = match_string.upper()
            identChars = identChars.upper()
        self.identChars = set(identChars)

    def _generateDefaultName(self):
        return repr(self.match)

    def parseImpl(self, instring, loc, doActions=True):
        errmsg = self.errmsg
        errloc = loc
        if self.caseless:
            if instring[loc : loc + self.matchLen].upper() == self.caselessmatch:
                if loc == 0 or instring[loc - 1].upper() not in self.identChars:
                    if (
                        loc >= len(instring) - self.matchLen
                        or instring[loc + self.matchLen].upper() not in self.identChars
                    ):
                        return loc + self.matchLen, self.match
                    else:
                        # followed by keyword char
                        errmsg += ", was immediately followed by keyword character"
                        errloc = loc + self.matchLen
                else:
                    # preceded by keyword char
                    errmsg += ", keyword was immediately preceded by keyword character"
                    errloc = loc - 1
            # else no match just raise plain exception

        else:
            if (
                instring[loc] == self.firstMatchChar
                and self.matchLen == 1
                or instring.startswith(self.match, loc)
            ):
                if loc == 0 or instring[loc - 1] not in self.identChars:
                    if (
                        loc >= len(instring) - self.matchLen
                        or instring[loc + self.matchLen] not in self.identChars
                    ):
                        return loc + self.matchLen, self.match
                    else:
                        # followed by keyword char
                        errmsg += (
                            ", keyword was immediately followed by keyword character"
                        )
                        errloc = loc + self.matchLen
                else:
                    # preceded by keyword char
                    errmsg += ", keyword was immediately preceded by keyword character"
                    errloc = loc - 1
            # else no match just raise plain exception

        raise ParseException(instring, errloc, errmsg, self)

    @staticmethod
    def set_default_keyword_chars(chars) -> None:
        """
        Overrides the default characters used by :class:`Keyword` expressions.
        """
        Keyword.DEFAULT_KEYWORD_CHARS = chars

    setDefaultKeywordChars = set_default_keyword_chars


class CaselessLiteral(Literal):
    """
    Token to match a specified string, ignoring case of letters.
    Note: the matched results will always be in the case of the given
    match string, NOT the case of the input text.

    Example::

        CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10")
        # -> ['CMD', 'CMD', 'CMD']

    (Contrast with example for :class:`CaselessKeyword`.)
    """

    def __init__(self, match_string: str = "", *, matchString: str = ""):
        match_string = matchString or match_string
        super().__init__(match_string.upper())
        # Preserve the defining literal.
        self.returnString = match_string
        self.errmsg = "Expected " + self.name

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc : loc + self.matchLen].upper() == self.match:
            return loc + self.matchLen, self.returnString
        raise ParseException(instring, loc, self.errmsg, self)


class CaselessKeyword(Keyword):
    """
    Caseless version of :class:`Keyword`.

    Example::

        CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10")
        # -> ['CMD', 'CMD']

    (Contrast with example for :class:`CaselessLiteral`.)
    """

    def __init__(
        self,
        match_string: str = "",
        ident_chars: typing.Optional[str] = None,
        *,
        matchString: str = "",
        identChars: typing.Optional[str] = None,
    ):
        identChars = identChars or ident_chars
        match_string = matchString or match_string
        super().__init__(match_string, identChars, caseless=True)


class CloseMatch(Token):
    """A variation on :class:`Literal` which matches "close" matches,
    that is, strings with at most 'n' mismatching characters.
    :class:`CloseMatch` takes parameters:

    - ``match_string`` - string to be matched
    - ``caseless`` - a boolean indicating whether to ignore casing when comparing characters
    - ``max_mismatches`` - (``default=1``) maximum number of
      mismatches allowed to count as a match

    The results from a successful parse will contain the matched text
    from the input string and the following named results:

    - ``mismatches`` - a list of the positions within the
      match_string where mismatches were found
    - ``original`` - the original match_string used to compare
      against the input string

    If ``mismatches`` is an empty list, then the match was an exact
    match.

    Example::

        patt = CloseMatch("ATCATCGAATGGA")
        patt.parse_string("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']})
        patt.parse_string("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1)

        # exact match
        patt.parse_string("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']})

        # close match allowing up to 2 mismatches
        patt = CloseMatch("ATCATCGAATGGA", max_mismatches=2)
        patt.parse_string("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']})
    """

    def __init__(
        self,
        match_string: str,
        max_mismatches: int = None,
        *,
        maxMismatches: int = 1,
        caseless=False,
    ):
        maxMismatches = max_mismatches if max_mismatches is not None else maxMismatches
        super().__init__()
        self.match_string = match_string
        self.maxMismatches = maxMismatches
        self.errmsg = "Expected {!r} (with up to {} mismatches)".format(
            self.match_string, self.maxMismatches
        )
        self.caseless = caseless
        self.mayIndexError = False
        self.mayReturnEmpty = False

    def _generateDefaultName(self):
        return "{}:{!r}".format(type(self).__name__, self.match_string)

    def parseImpl(self, instring, loc, doActions=True):
        start = loc
        instrlen = len(instring)
        maxloc = start + len(self.match_string)

        if maxloc <= instrlen:
            match_string = self.match_string
            match_stringloc = 0
            mismatches = []
            maxMismatches = self.maxMismatches

            for match_stringloc, s_m in enumerate(
                zip(instring[loc:maxloc], match_string)
            ):
                src, mat = s_m
                if self.caseless:
                    src, mat = src.lower(), mat.lower()

                if src != mat:
                    mismatches.append(match_stringloc)
                    if len(mismatches) > maxMismatches:
                        break
            else:
                loc = start + match_stringloc + 1
                results = ParseResults([instring[start:loc]])
                results["original"] = match_string
                results["mismatches"] = mismatches
                return loc, results

        raise ParseException(instring, loc, self.errmsg, self)


class Word(Token):
    """Token for matching words composed of allowed character sets.
    Parameters:
    - ``init_chars`` - string of all characters that should be used to
      match as a word; "ABC" will match "AAA", "ABAB", "CBAC", etc.;
      if ``body_chars`` is also specified, then this is the string of
      initial characters
    - ``body_chars`` - string of characters that
      can be used for matching after a matched initial character as
      given in ``init_chars``; if omitted, same as the initial characters
      (default=``None``)
    - ``min`` - minimum number of characters to match (default=1)
    - ``max`` - maximum number of characters to match (default=0)
    - ``exact`` - exact number of characters to match (default=0)
    - ``as_keyword`` - match as a keyword (default=``False``)
    - ``exclude_chars`` - characters that might be
      found in the input ``body_chars`` string but which should not be
      accepted for matching ;useful to define a word of all
      printables except for one or two characters, for instance
      (default=``None``)

    :class:`srange` is useful for defining custom character set strings
    for defining :class:`Word` expressions, using range notation from
    regular expression character sets.

    A common mistake is to use :class:`Word` to match a specific literal
    string, as in ``Word("Address")``. Remember that :class:`Word`
    uses the string argument to define *sets* of matchable characters.
    This expression would match "Add", "AAA", "dAred", or any other word
    made up of the characters 'A', 'd', 'r', 'e', and 's'. To match an
    exact literal string, use :class:`Literal` or :class:`Keyword`.

    pyparsing includes helper strings for building Words:

    - :class:`alphas`
    - :class:`nums`
    - :class:`alphanums`
    - :class:`hexnums`
    - :class:`alphas8bit` (alphabetic characters in ASCII range 128-255
      - accented, tilded, umlauted, etc.)
    - :class:`punc8bit` (non-alphabetic characters in ASCII range
      128-255 - currency, symbols, superscripts, diacriticals, etc.)
    - :class:`printables` (any non-whitespace character)

    ``alphas``, ``nums``, and ``printables`` are also defined in several
    Unicode sets - see :class:`pyparsing_unicode``.

    Example::

        # a word composed of digits
        integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9"))

        # a word with a leading capital, and zero or more lowercase
        capital_word = Word(alphas.upper(), alphas.lower())

        # hostnames are alphanumeric, with leading alpha, and '-'
        hostname = Word(alphas, alphanums + '-')

        # roman numeral (not a strict parser, accepts invalid mix of characters)
        roman = Word("IVXLCDM")

        # any string of non-whitespace characters, except for ','
        csv_value = Word(printables, exclude_chars=",")
    """

    def __init__(
        self,
        init_chars: str = "",
        body_chars: typing.Optional[str] = None,
        min: int = 1,
        max: int = 0,
        exact: int = 0,
        as_keyword: bool = False,
        exclude_chars: typing.Optional[str] = None,
        *,
        initChars: typing.Optional[str] = None,
        bodyChars: typing.Optional[str] = None,
        asKeyword: bool = False,
        excludeChars: typing.Optional[str] = None,
    ):
        initChars = initChars or init_chars
        bodyChars = bodyChars or body_chars
        asKeyword = asKeyword or as_keyword
        excludeChars = excludeChars or exclude_chars
        super().__init__()
        if not initChars:
            raise ValueError(
                "invalid {}, initChars cannot be empty string".format(
                    type(self).__name__
                )
            )

        initChars = set(initChars)
        self.initChars = initChars
        if excludeChars:
            excludeChars = set(excludeChars)
            initChars -= excludeChars
            if bodyChars:
                bodyChars = set(bodyChars) - excludeChars
        self.initCharsOrig = "".join(sorted(initChars))

        if bodyChars:
            self.bodyCharsOrig = "".join(sorted(bodyChars))
            self.bodyChars = set(bodyChars)
        else:
            self.bodyCharsOrig = "".join(sorted(initChars))
            self.bodyChars = set(initChars)

        self.maxSpecified = max > 0

        if min < 1:
            raise ValueError(
                "cannot specify a minimum length < 1; use Opt(Word()) if zero-length word is permitted"
            )

        self.minLen = min

        if max > 0:
            self.maxLen = max
        else:
            self.maxLen = _MAX_INT

        if exact > 0:
            self.maxLen = exact
            self.minLen = exact

        self.errmsg = "Expected " + self.name
        self.mayIndexError = False
        self.asKeyword = asKeyword

        # see if we can make a regex for this Word
        if " " not in self.initChars | self.bodyChars and (min == 1 and exact == 0):
            if self.bodyChars == self.initChars:
                if max == 0:
                    repeat = "+"
                elif max == 1:
                    repeat = ""
                else:
                    repeat = "{{{},{}}}".format(
                        self.minLen, "" if self.maxLen == _MAX_INT else self.maxLen
                    )
                self.reString = "[{}]{}".format(
                    _collapse_string_to_ranges(self.initChars),
                    repeat,
                )
            elif len(self.initChars) == 1:
                if max == 0:
                    repeat = "*"
                else:
                    repeat = "{{0,{}}}".format(max - 1)
                self.reString = "{}[{}]{}".format(
                    re.escape(self.initCharsOrig),
                    _collapse_string_to_ranges(self.bodyChars),
                    repeat,
                )
            else:
                if max == 0:
                    repeat = "*"
                elif max == 2:
                    repeat = ""
                else:
                    repeat = "{{0,{}}}".format(max - 1)
                self.reString = "[{}][{}]{}".format(
                    _collapse_string_to_ranges(self.initChars),
                    _collapse_string_to_ranges(self.bodyChars),
                    repeat,
                )
            if self.asKeyword:
                self.reString = r"\b" + self.reString + r"\b"

            try:
                self.re = re.compile(self.reString)
            except re.error:
                self.re = None
            else:
                self.re_match = self.re.match
                self.__class__ = _WordRegex

    def _generateDefaultName(self):
        def charsAsStr(s):
            max_repr_len = 16
            s = _collapse_string_to_ranges(s, re_escape=False)
            if len(s) > max_repr_len:
                return s[: max_repr_len - 3] + "..."
            else:
                return s

        if self.initChars != self.bodyChars:
            base = "W:({}, {})".format(
                charsAsStr(self.initChars), charsAsStr(self.bodyChars)
            )
        else:
            base = "W:({})".format(charsAsStr(self.initChars))

        # add length specification
        if self.minLen > 1 or self.maxLen != _MAX_INT:
            if self.minLen == self.maxLen:
                if self.minLen == 1:
                    return base[2:]
                else:
                    return base + "{{{}}}".format(self.minLen)
            elif self.maxLen == _MAX_INT:
                return base + "{{{},...}}".format(self.minLen)
            else:
                return base + "{{{},{}}}".format(self.minLen, self.maxLen)
        return base

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] not in self.initChars:
            raise ParseException(instring, loc, self.errmsg, self)

        start = loc
        loc += 1
        instrlen = len(instring)
        bodychars = self.bodyChars
        maxloc = start + self.maxLen
        maxloc = min(maxloc, instrlen)
        while loc < maxloc and instring[loc] in bodychars:
            loc += 1

        throwException = False
        if loc - start < self.minLen:
            throwException = True
        elif self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
            throwException = True
        elif self.asKeyword:
            if (
                start > 0
                and instring[start - 1] in bodychars
                or loc < instrlen
                and instring[loc] in bodychars
            ):
                throwException = True

        if throwException:
            raise ParseException(instring, loc, self.errmsg, self)

        return loc, instring[start:loc]


class _WordRegex(Word):
    def parseImpl(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        return loc, result.group()


class Char(_WordRegex):
    """A short-cut class for defining :class:`Word` ``(characters, exact=1)``,
    when defining a match of any single character in a string of
    characters.
    """

    def __init__(
        self,
        charset: str,
        as_keyword: bool = False,
        exclude_chars: typing.Optional[str] = None,
        *,
        asKeyword: bool = False,
        excludeChars: typing.Optional[str] = None,
    ):
        asKeyword = asKeyword or as_keyword
        excludeChars = excludeChars or exclude_chars
        super().__init__(
            charset, exact=1, asKeyword=asKeyword, excludeChars=excludeChars
        )
        self.reString = "[{}]".format(_collapse_string_to_ranges(self.initChars))
        if asKeyword:
            self.reString = r"\b{}\b".format(self.reString)
        self.re = re.compile(self.reString)
        self.re_match = self.re.match


class Regex(Token):
    r"""Token for matching strings that match a given regular
    expression. Defined with string specifying the regular expression in
    a form recognized by the stdlib Python  `re module <https://docs.python.org/3/library/re.html>`_.
    If the given regex contains named groups (defined using ``(?P<name>...)``),
    these will be preserved as named :class:`ParseResults`.

    If instead of the Python stdlib ``re`` module you wish to use a different RE module
    (such as the ``regex`` module), you can do so by building your ``Regex`` object with
    a compiled RE that was compiled using ``regex``.

    Example::

        realnum = Regex(r"[+-]?\d+\.\d*")
        # ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression
        roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")

        # named fields in a regex will be returned as named results
        date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)')

        # the Regex class will accept re's compiled using the regex module
        import regex
        parser = pp.Regex(regex.compile(r'[0-9]'))
    """

    def __init__(
        self,
        pattern: Any,
        flags: Union[re.RegexFlag, int] = 0,
        as_group_list: bool = False,
        as_match: bool = False,
        *,
        asGroupList: bool = False,
        asMatch: bool = False,
    ):
        """The parameters ``pattern`` and ``flags`` are passed
        to the ``re.compile()`` function as-is. See the Python
        `re module <https://docs.python.org/3/library/re.html>`_ module for an
        explanation of the acceptable patterns and flags.
        """
        super().__init__()
        asGroupList = asGroupList or as_group_list
        asMatch = asMatch or as_match

        if isinstance(pattern, str_type):
            if not pattern:
                raise ValueError("null string passed to Regex; use Empty() instead")

            self._re = None
            self.reString = self.pattern = pattern
            self.flags = flags

        elif hasattr(pattern, "pattern") and hasattr(pattern, "match"):
            self._re = pattern
            self.pattern = self.reString = pattern.pattern
            self.flags = flags

        else:
            raise TypeError(
                "Regex may only be constructed with a string or a compiled RE object"
            )

        self.errmsg = "Expected " + self.name
        self.mayIndexError = False
        self.asGroupList = asGroupList
        self.asMatch = asMatch
        if self.asGroupList:
            self.parseImpl = self.parseImplAsGroupList
        if self.asMatch:
            self.parseImpl = self.parseImplAsMatch

    @cached_property
    def re(self):
        if self._re:
            return self._re
        else:
            try:
                return re.compile(self.pattern, self.flags)
            except re.error:
                raise ValueError(
                    "invalid pattern ({!r}) passed to Regex".format(self.pattern)
                )

    @cached_property
    def re_match(self):
        return self.re.match

    @cached_property
    def mayReturnEmpty(self):
        return self.re_match("") is not None

    def _generateDefaultName(self):
        return "Re:({})".format(repr(self.pattern).replace("\\\\", "\\"))

    def parseImpl(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = ParseResults(result.group())
        d = result.groupdict()
        if d:
            for k, v in d.items():
                ret[k] = v
        return loc, ret

    def parseImplAsGroupList(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = result.groups()
        return loc, ret

    def parseImplAsMatch(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = result
        return loc, ret

    def sub(self, repl: str) -> ParserElement:
        r"""
        Return :class:`Regex` with an attached parse action to transform the parsed
        result as if called using `re.sub(expr, repl, string) <https://docs.python.org/3/library/re.html#re.sub>`_.

        Example::

            make_html = Regex(r"(\w+):(.*?):").sub(r"<\1>\2</\1>")
            print(make_html.transform_string("h1:main title:"))
            # prints "<h1>main title</h1>"
        """
        if self.asGroupList:
            raise TypeError("cannot use sub() with Regex(asGroupList=True)")

        if self.asMatch and callable(repl):
            raise TypeError("cannot use sub() with a callable with Regex(asMatch=True)")

        if self.asMatch:

            def pa(tokens):
                return tokens[0].expand(repl)

        else:

            def pa(tokens):
                return self.re.sub(repl, tokens[0])

        return self.add_parse_action(pa)


class QuotedString(Token):
    r"""
    Token for matching strings that are delimited by quoting characters.

    Defined with the following parameters:

    - ``quote_char`` - string of one or more characters defining the
      quote delimiting string
    - ``esc_char`` - character to re_escape quotes, typically backslash
      (default= ``None``)
    - ``esc_quote`` - special quote sequence to re_escape an embedded quote
      string (such as SQL's ``""`` to re_escape an embedded ``"``)
      (default= ``None``)
    - ``multiline`` - boolean indicating whether quotes can span
      multiple lines (default= ``False``)
    - ``unquote_results`` - boolean indicating whether the matched text
      should be unquoted (default= ``True``)
    - ``end_quote_char`` - string of one or more characters defining the
      end of the quote delimited string (default= ``None``  => same as
      quote_char)
    - ``convert_whitespace_escapes`` - convert escaped whitespace
      (``'\t'``, ``'\n'``, etc.) to actual whitespace
      (default= ``True``)

    Example::

        qs = QuotedString('"')
        print(qs.search_string('lsjdf "This is the quote" sldjf'))
        complex_qs = QuotedString('{{', end_quote_char='}}')
        print(complex_qs.search_string('lsjdf {{This is the "quote"}} sldjf'))
        sql_qs = QuotedString('"', esc_quote='""')
        print(sql_qs.search_string('lsjdf "This is the quote with ""embedded"" quotes" sldjf'))

    prints::

        [['This is the quote']]
        [['This is the "quote"']]
        [['This is the quote with "embedded" quotes']]
    """
    ws_map = ((r"\t", "\t"), (r"\n", "\n"), (r"\f", "\f"), (r"\r", "\r"))

    def __init__(
        self,
        quote_char: str = "",
        esc_char: typing.Optional[str] = None,
        esc_quote: typing.Optional[str] = None,
        multiline: bool = False,
        unquote_results: bool = True,
        end_quote_char: typing.Optional[str] = None,
        convert_whitespace_escapes: bool = True,
        *,
        quoteChar: str = "",
        escChar: typing.Optional[str] = None,
        escQuote: typing.Optional[str] = None,
        unquoteResults: bool = True,
        endQuoteChar: typing.Optional[str] = None,
        convertWhitespaceEscapes: bool = True,
    ):
        super().__init__()
        escChar = escChar or esc_char
        escQuote = escQuote or esc_quote
        unquoteResults = unquoteResults and unquote_results
        endQuoteChar = endQuoteChar or end_quote_char
        convertWhitespaceEscapes = (
            convertWhitespaceEscapes and convert_whitespace_escapes
        )
        quote_char = quoteChar or quote_char

        # remove white space from quote chars - wont work anyway
        quote_char = quote_char.strip()
        if not quote_char:
            raise ValueError("quote_char cannot be the empty string")

        if endQuoteChar is None:
            endQuoteChar = quote_char
        else:
            endQuoteChar = endQuoteChar.strip()
            if not endQuoteChar:
                raise ValueError("endQuoteChar cannot be the empty string")

        self.quoteChar = quote_char
        self.quoteCharLen = len(quote_char)
        self.firstQuoteChar = quote_char[0]
        self.endQuoteChar = endQuoteChar
        self.endQuoteCharLen = len(endQuoteChar)
        self.escChar = escChar
        self.escQuote = escQuote
        self.unquoteResults = unquoteResults
        self.convertWhitespaceEscapes = convertWhitespaceEscapes

        sep = ""
        inner_pattern = ""

        if escQuote:
            inner_pattern += r"{}(?:{})".format(sep, re.escape(escQuote))
            sep = "|"

        if escChar:
            inner_pattern += r"{}(?:{}.)".format(sep, re.escape(escChar))
            sep = "|"
            self.escCharReplacePattern = re.escape(self.escChar) + "(.)"

        if len(self.endQuoteChar) > 1:
            inner_pattern += (
                "{}(?:".format(sep)
                + "|".join(
                    "(?:{}(?!{}))".format(
                        re.escape(self.endQuoteChar[:i]),
                        re.escape(self.endQuoteChar[i:]),
                    )
                    for i in range(len(self.endQuoteChar) - 1, 0, -1)
                )
                + ")"
            )
            sep = "|"

        if multiline:
            self.flags = re.MULTILINE | re.DOTALL
            inner_pattern += r"{}(?:[^{}{}])".format(
                sep,
                _escape_regex_range_chars(self.endQuoteChar[0]),
                (_escape_regex_range_chars(escChar) if escChar is not None else ""),
            )
        else:
            self.flags = 0
            inner_pattern += r"{}(?:[^{}\n\r{}])".format(
                sep,
                _escape_regex_range_chars(self.endQuoteChar[0]),
                (_escape_regex_range_chars(escChar) if escChar is not None else ""),
            )

        self.pattern = "".join(
            [
                re.escape(self.quoteChar),
                "(?:",
                inner_pattern,
                ")*",
                re.escape(self.endQuoteChar),
            ]
        )

        try:
            self.re = re.compile(self.pattern, self.flags)
            self.reString = self.pattern
            self.re_match = self.re.match
        except re.error:
            raise ValueError(
                "invalid pattern {!r} passed to Regex".format(self.pattern)
            )

        self.errmsg = "Expected " + self.name
        self.mayIndexError = False
        self.mayReturnEmpty = True

    def _generateDefaultName(self):
        if self.quoteChar == self.endQuoteChar and isinstance(self.quoteChar, str_type):
            return "string enclosed in {!r}".format(self.quoteChar)

        return "quoted string, starting with {} ending with {}".format(
            self.quoteChar, self.endQuoteChar
        )

    def parseImpl(self, instring, loc, doActions=True):
        result = (
            instring[loc] == self.firstQuoteChar
            and self.re_match(instring, loc)
            or None
        )
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = result.group()

        if self.unquoteResults:

            # strip off quotes
            ret = ret[self.quoteCharLen : -self.endQuoteCharLen]

            if isinstance(ret, str_type):
                # replace escaped whitespace
                if "\\" in ret and self.convertWhitespaceEscapes:
                    for wslit, wschar in self.ws_map:
                        ret = ret.replace(wslit, wschar)

                # replace escaped characters
                if self.escChar:
                    ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret)

                # replace escaped quotes
                if self.escQuote:
                    ret = ret.replace(self.escQuote, self.endQuoteChar)

        return loc, ret


class CharsNotIn(Token):
    """Token for matching words composed of characters *not* in a given
    set (will include whitespace in matched characters if not listed in
    the provided exclusion set - see example). Defined with string
    containing all disallowed characters, and an optional minimum,
    maximum, and/or exact length.  The default value for ``min`` is
    1 (a minimum value < 1 is not valid); the default values for
    ``max`` and ``exact`` are 0, meaning no maximum or exact
    length restriction.

    Example::

        # define a comma-separated-value as anything that is not a ','
        csv_value = CharsNotIn(',')
        print(delimited_list(csv_value).parse_string("dkls,lsdkjf,s12 34,@!#,213"))

    prints::

        ['dkls', 'lsdkjf', 's12 34', '@!#', '213']
    """

    def __init__(
        self,
        not_chars: str = "",
        min: int = 1,
        max: int = 0,
        exact: int = 0,
        *,
        notChars: str = "",
    ):
        super().__init__()
        self.skipWhitespace = False
        self.notChars = not_chars or notChars
        self.notCharsSet = set(self.notChars)

        if min < 1:
            raise ValueError(
                "cannot specify a minimum length < 1; use "
                "Opt(CharsNotIn()) if zero-length char group is permitted"
            )

        self.minLen = min

        if max > 0:
            self.maxLen = max
        else:
            self.maxLen = _MAX_INT

        if exact > 0:
            self.maxLen = exact
            self.minLen = exact

        self.errmsg = "Expected " + self.name
        self.mayReturnEmpty = self.minLen == 0
        self.mayIndexError = False

    def _generateDefaultName(self):
        not_chars_str = _collapse_string_to_ranges(self.notChars)
        if len(not_chars_str) > 16:
            return "!W:({}...)".format(self.notChars[: 16 - 3])
        else:
            return "!W:({})".format(self.notChars)

    def parseImpl(self, instring, loc, doActions=True):
        notchars = self.notCharsSet
        if instring[loc] in notchars:
            raise ParseException(instring, loc, self.errmsg, self)

        start = loc
        loc += 1
        maxlen = min(start + self.maxLen, len(instring))
        while loc < maxlen and instring[loc] not in notchars:
            loc += 1

        if loc - start < self.minLen:
            raise ParseException(instring, loc, self.errmsg, self)

        return loc, instring[start:loc]


class White(Token):
    """Special matching class for matching whitespace.  Normally,
    whitespace is ignored by pyparsing grammars.  This class is included
    when some whitespace structures are significant.  Define with
    a string containing the whitespace characters to be matched; default
    is ``" \\t\\r\\n"``.  Also takes optional ``min``,
    ``max``, and ``exact`` arguments, as defined for the
    :class:`Word` class.
    """

    whiteStrs = {
        " ": "<SP>",
        "\t": "<TAB>",
        "\n": "<LF>",
        "\r": "<CR>",
        "\f": "<FF>",
        "\u00A0": "<NBSP>",
        "\u1680": "<OGHAM_SPACE_MARK>",
        "\u180E": "<MONGOLIAN_VOWEL_SEPARATOR>",
        "\u2000": "<EN_QUAD>",
        "\u2001": "<EM_QUAD>",
        "\u2002": "<EN_SPACE>",
        "\u2003": "<EM_SPACE>",
        "\u2004": "<THREE-PER-EM_SPACE>",
        "\u2005": "<FOUR-PER-EM_SPACE>",
        "\u2006": "<SIX-PER-EM_SPACE>",
        "\u2007": "<FIGURE_SPACE>",
        "\u2008": "<PUNCTUATION_SPACE>",
        "\u2009": "<THIN_SPACE>",
        "\u200A": "<HAIR_SPACE>",
        "\u200B": "<ZERO_WIDTH_SPACE>",
        "\u202F": "<NNBSP>",
        "\u205F": "<MMSP>",
        "\u3000": "<IDEOGRAPHIC_SPACE>",
    }

    def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0):
        super().__init__()
        self.matchWhite = ws
        self.set_whitespace_chars(
            "".join(c for c in self.whiteStrs if c not in self.matchWhite),
            copy_defaults=True,
        )
        # self.leave_whitespace()
        self.mayReturnEmpty = True
        self.errmsg = "Expected " + self.name

        self.minLen = min

        if max > 0:
            self.maxLen = max
        else:
            self.maxLen = _MAX_INT

        if exact > 0:
            self.maxLen = exact
            self.minLen = exact

    def _generateDefaultName(self):
        return "".join(White.whiteStrs[c] for c in self.matchWhite)

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] not in self.matchWhite:
            raise ParseException(instring, loc, self.errmsg, self)
        start = loc
        loc += 1
        maxloc = start + self.maxLen
        maxloc = min(maxloc, len(instring))
        while loc < maxloc and instring[loc] in self.matchWhite:
            loc += 1

        if loc - start < self.minLen:
            raise ParseException(instring, loc, self.errmsg, self)

        return loc, instring[start:loc]


class PositionToken(Token):
    def __init__(self):
        super().__init__()
        self.mayReturnEmpty = True
        self.mayIndexError = False


class GoToColumn(PositionToken):
    """Token to advance to a specific column of input text; useful for
    tabular report scraping.
    """

    def __init__(self, colno: int):
        super().__init__()
        self.col = colno

    def preParse(self, instring, loc):
        if col(loc, instring) != self.col:
            instrlen = len(instring)
            if self.ignoreExprs:
                loc = self._skipIgnorables(instring, loc)
            while (
                loc < instrlen
                and instring[loc].isspace()
                and col(loc, instring) != self.col
            ):
                loc += 1
        return loc

    def parseImpl(self, instring, loc, doActions=True):
        thiscol = col(loc, instring)
        if thiscol > self.col:
            raise ParseException(instring, loc, "Text not in expected column", self)
        newloc = loc + self.col - thiscol
        ret = instring[loc:newloc]
        return newloc, ret


class LineStart(PositionToken):
    r"""Matches if current position is at the beginning of a line within
    the parse string

    Example::

        test = '''\
        AAA this line
        AAA and this line
          AAA but not this one
        B AAA and definitely not this one
        '''

        for t in (LineStart() + 'AAA' + restOfLine).search_string(test):
            print(t)

    prints::

        ['AAA', ' this line']
        ['AAA', ' and this line']

    """

    def __init__(self):
        super().__init__()
        self.leave_whitespace()
        self.orig_whiteChars = set() | self.whiteChars
        self.whiteChars.discard("\n")
        self.skipper = Empty().set_whitespace_chars(self.whiteChars)
        self.errmsg = "Expected start of line"

    def preParse(self, instring, loc):
        if loc == 0:
            return loc
        else:
            ret = self.skipper.preParse(instring, loc)
            if "\n" in self.orig_whiteChars:
                while instring[ret : ret + 1] == "\n":
                    ret = self.skipper.preParse(instring, ret + 1)
            return ret

    def parseImpl(self, instring, loc, doActions=True):
        if col(loc, instring) == 1:
            return loc, []
        raise ParseException(instring, loc, self.errmsg, self)


class LineEnd(PositionToken):
    """Matches if current position is at the end of a line within the
    parse string
    """

    def __init__(self):
        super().__init__()
        self.whiteChars.discard("\n")
        self.set_whitespace_chars(self.whiteChars, copy_defaults=False)
        self.errmsg = "Expected end of line"

    def parseImpl(self, instring, loc, doActions=True):
        if loc < len(instring):
            if instring[loc] == "\n":
                return loc + 1, "\n"
            else:
                raise ParseException(instring, loc, self.errmsg, self)
        elif loc == len(instring):
            return loc + 1, []
        else:
            raise ParseException(instring, loc, self.errmsg, self)


class StringStart(PositionToken):
    """Matches if current position is at the beginning of the parse
    string
    """

    def __init__(self):
        super().__init__()
        self.errmsg = "Expected start of text"

    def parseImpl(self, instring, loc, doActions=True):
        if loc != 0:
            # see if entire string up to here is just whitespace and ignoreables
            if loc != self.preParse(instring, 0):
                raise ParseException(instring, loc, self.errmsg, self)
        return loc, []


class StringEnd(PositionToken):
    """
    Matches if current position is at the end of the parse string
    """

    def __init__(self):
        super().__init__()
        self.errmsg = "Expected end of text"

    def parseImpl(self, instring, loc, doActions=True):
        if loc < len(instring):
            raise ParseException(instring, loc, self.errmsg, self)
        elif loc == len(instring):
            return loc + 1, []
        elif loc > len(instring):
            return loc, []
        else:
            raise ParseException(instring, loc, self.errmsg, self)


class WordStart(PositionToken):
    """Matches if the current position is at the beginning of a
    :class:`Word`, and is not preceded by any character in a given
    set of ``word_chars`` (default= ``printables``). To emulate the
    ``\b`` behavior of regular expressions, use
    ``WordStart(alphanums)``. ``WordStart`` will also match at
    the beginning of the string being parsed, or at the beginning of
    a line.
    """

    def __init__(self, word_chars: str = printables, *, wordChars: str = printables):
        wordChars = word_chars if wordChars == printables else wordChars
        super().__init__()
        self.wordChars = set(wordChars)
        self.errmsg = "Not at the start of a word"

    def parseImpl(self, instring, loc, doActions=True):
        if loc != 0:
            if (
                instring[loc - 1] in self.wordChars
                or instring[loc] not in self.wordChars
            ):
                raise ParseException(instring, loc, self.errmsg, self)
        return loc, []


class WordEnd(PositionToken):
    """Matches if the current position is at the end of a :class:`Word`,
    and is not followed by any character in a given set of ``word_chars``
    (default= ``printables``). To emulate the ``\b`` behavior of
    regular expressions, use ``WordEnd(alphanums)``. ``WordEnd``
    will also match at the end of the string being parsed, or at the end
    of a line.
    """

    def __init__(self, word_chars: str = printables, *, wordChars: str = printables):
        wordChars = word_chars if wordChars == printables else wordChars
        super().__init__()
        self.wordChars = set(wordChars)
        self.skipWhitespace = False
        self.errmsg = "Not at the end of a word"

    def parseImpl(self, instring, loc, doActions=True):
        instrlen = len(instring)
        if instrlen > 0 and loc < instrlen:
            if (
                instring[loc] in self.wordChars
                or instring[loc - 1] not in self.wordChars
            ):
                raise ParseException(instring, loc, self.errmsg, self)
        return loc, []


class ParseExpression(ParserElement):
    """Abstract subclass of ParserElement, for combining and
    post-processing parsed tokens.
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
        super().__init__(savelist)
        self.exprs: List[ParserElement]
        if isinstance(exprs, _generatorType):
            exprs = list(exprs)

        if isinstance(exprs, str_type):
            self.exprs = [self._literalStringClass(exprs)]
        elif isinstance(exprs, ParserElement):
            self.exprs = [exprs]
        elif isinstance(exprs, Iterable):
            exprs = list(exprs)
            # if sequence of strings provided, wrap with Literal
            if any(isinstance(expr, str_type) for expr in exprs):
                exprs = (
                    self._literalStringClass(e) if isinstance(e, str_type) else e
                    for e in exprs
                )
            self.exprs = list(exprs)
        else:
            try:
                self.exprs = list(exprs)
            except TypeError:
                self.exprs = [exprs]
        self.callPreparse = False

    def recurse(self) -> Sequence[ParserElement]:
        return self.exprs[:]

    def append(self, other) -> ParserElement:
        self.exprs.append(other)
        self._defaultName = None
        return self

    def leave_whitespace(self, recursive: bool = True) -> ParserElement:
        """
        Extends ``leave_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on
           all contained expressions.
        """
        super().leave_whitespace(recursive)

        if recursive:
            self.exprs = [e.copy() for e in self.exprs]
            for e in self.exprs:
                e.leave_whitespace(recursive)
        return self

    def ignore_whitespace(self, recursive: bool = True) -> ParserElement:
        """
        Extends ``ignore_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on
           all contained expressions.
        """
        super().ignore_whitespace(recursive)
        if recursive:
            self.exprs = [e.copy() for e in self.exprs]
            for e in self.exprs:
                e.ignore_whitespace(recursive)
        return self

    def ignore(self, other) -> ParserElement:
        if isinstance(other, Suppress):
            if other not in self.ignoreExprs:
                super().ignore(other)
                for e in self.exprs:
                    e.ignore(self.ignoreExprs[-1])
        else:
            super().ignore(other)
            for e in self.exprs:
                e.ignore(self.ignoreExprs[-1])
        return self

    def _generateDefaultName(self):
        return "{}:({})".format(self.__class__.__name__, str(self.exprs))

    def streamline(self) -> ParserElement:
        if self.streamlined:
            return self

        super().streamline()

        for e in self.exprs:
            e.streamline()

        # collapse nested :class:`And`'s of the form ``And(And(And(a, b), c), d)`` to ``And(a, b, c, d)``
        # but only if there are no parse actions or resultsNames on the nested And's
        # (likewise for :class:`Or`'s and :class:`MatchFirst`'s)
        if len(self.exprs) == 2:
            other = self.exprs[0]
            if (
                isinstance(other, self.__class__)
                and not other.parseAction
                and other.resultsName is None
                and not other.debug
            ):
                self.exprs = other.exprs[:] + [self.exprs[1]]
                self._defaultName = None
                self.mayReturnEmpty |= other.mayReturnEmpty
                self.mayIndexError |= other.mayIndexError

            other = self.exprs[-1]
            if (
                isinstance(other, self.__class__)
                and not other.parseAction
                and other.resultsName is None
                and not other.debug
            ):
                self.exprs = self.exprs[:-1] + other.exprs[:]
                self._defaultName = None
                self.mayReturnEmpty |= other.mayReturnEmpty
                self.mayIndexError |= other.mayIndexError

        self.errmsg = "Expected " + str(self)

        return self

    def validate(self, validateTrace=None) -> None:
        tmp = (validateTrace if validateTrace is not None else [])[:] + [self]
        for e in self.exprs:
            e.validate(tmp)
        self._checkRecursion([])

    def copy(self) -> ParserElement:
        ret = super().copy()
        ret.exprs = [e.copy() for e in self.exprs]
        return ret

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_ungrouped_named_tokens_in_collection
            and Diagnostics.warn_ungrouped_named_tokens_in_collection
            not in self.suppress_warnings_
        ):
            for e in self.exprs:
                if (
                    isinstance(e, ParserElement)
                    and e.resultsName
                    and Diagnostics.warn_ungrouped_named_tokens_in_collection
                    not in e.suppress_warnings_
                ):
                    warnings.warn(
                        "{}: setting results name {!r} on {} expression "
                        "collides with {!r} on contained expression".format(
                            "warn_ungrouped_named_tokens_in_collection",
                            name,
                            type(self).__name__,
                            e.resultsName,
                        ),
                        stacklevel=3,
                    )

        return super()._setResultsName(name, listAllMatches)

    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class And(ParseExpression):
    """
    Requires all given :class:`ParseExpression` s to be found in the given order.
    Expressions may be separated by whitespace.
    May be constructed using the ``'+'`` operator.
    May also be constructed using the ``'-'`` operator, which will
    suppress backtracking.

    Example::

        integer = Word(nums)
        name_expr = Word(alphas)[1, ...]

        expr = And([integer("id"), name_expr("name"), integer("age")])
        # more easily written as:
        expr = integer("id") + name_expr("name") + integer("age")
    """

    class _ErrorStop(Empty):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.leave_whitespace()

        def _generateDefaultName(self):
            return "-"

    def __init__(
        self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True
    ):
        exprs: List[ParserElement] = list(exprs_arg)
        if exprs and Ellipsis in exprs:
            tmp = []
            for i, expr in enumerate(exprs):
                if expr is Ellipsis:
                    if i < len(exprs) - 1:
                        skipto_arg: ParserElement = (Empty() + exprs[i + 1]).exprs[-1]
                        tmp.append(SkipTo(skipto_arg)("_skipped*"))
                    else:
                        raise Exception(
                            "cannot construct And with sequence ending in ..."
                        )
                else:
                    tmp.append(expr)
            exprs[:] = tmp
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
            if not isinstance(self.exprs[0], White):
                self.set_whitespace_chars(
                    self.exprs[0].whiteChars,
                    copy_defaults=self.exprs[0].copyDefaultWhiteChars,
                )
                self.skipWhitespace = self.exprs[0].skipWhitespace
            else:
                self.skipWhitespace = False
        else:
            self.mayReturnEmpty = True
        self.callPreparse = True

    def streamline(self) -> ParserElement:
        # collapse any _PendingSkip's
        if self.exprs:
            if any(
                isinstance(e, ParseExpression)
                and e.exprs
                and isinstance(e.exprs[-1], _PendingSkip)
                for e in self.exprs[:-1]
            ):
                for i, e in enumerate(self.exprs[:-1]):
                    if e is None:
                        continue
                    if (
                        isinstance(e, ParseExpression)
                        and e.exprs
                        and isinstance(e.exprs[-1], _PendingSkip)
                    ):
                        e.exprs[-1] = e.exprs[-1] + self.exprs[i + 1]
                        self.exprs[i + 1] = None
                self.exprs = [e for e in self.exprs if e is not None]

        super().streamline()

        # link any IndentedBlocks to the prior expression
        for prev, cur in zip(self.exprs, self.exprs[1:]):
            # traverse cur or any first embedded expr of cur looking for an IndentedBlock
            # (but watch out for recursive grammar)
            seen = set()
            while cur:
                if id(cur) in seen:
                    break
                seen.add(id(cur))
                if isinstance(cur, IndentedBlock):
                    prev.add_parse_action(
                        lambda s, l, t, cur_=cur: setattr(
                            cur_, "parent_anchor", col(l, s)
                        )
                    )
                    break
                subs = cur.recurse()
                cur = next(iter(subs), None)

        self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
        return self

    def parseImpl(self, instring, loc, doActions=True):
        # pass False as callPreParse arg to _parse for first element, since we already
        # pre-parsed the string as part of our And pre-parsing
        loc, resultlist = self.exprs[0]._parse(
            instring, loc, doActions, callPreParse=False
        )
        errorStop = False
        for e in self.exprs[1:]:
            # if isinstance(e, And._ErrorStop):
            if type(e) is And._ErrorStop:
                errorStop = True
                continue
            if errorStop:
                try:
                    loc, exprtokens = e._parse(instring, loc, doActions)
                except ParseSyntaxException:
                    raise
                except ParseBaseException as pe:
                    pe.__traceback__ = None
                    raise ParseSyntaxException._from_exception(pe)
                except IndexError:
                    raise ParseSyntaxException(
                        instring, len(instring), self.errmsg, self
                    )
            else:
                loc, exprtokens = e._parse(instring, loc, doActions)
            if exprtokens or exprtokens.haskeys():
                resultlist += exprtokens
        return loc, resultlist

    def __iadd__(self, other):
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        return self.append(other)  # And([self, other])

    def _checkRecursion(self, parseElementList):
        subRecCheckList = parseElementList[:] + [self]
        for e in self.exprs:
            e._checkRecursion(subRecCheckList)
            if not e.mayReturnEmpty:
                break

    def _generateDefaultName(self):
        inner = " ".join(str(e) for e in self.exprs)
        # strip off redundant inner {}'s
        while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}":
            inner = inner[1:-1]
        return "{" + inner + "}"


class Or(ParseExpression):
    """Requires that at least one :class:`ParseExpression` is found. If
    two expressions match, the expression that matches the longest
    string will be used. May be constructed using the ``'^'``
    operator.

    Example::

        # construct Or using '^' operator

        number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums))
        print(number.search_string("123 3.1416 789"))

    prints::

        [['123'], ['3.1416'], ['789']]
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.skipWhitespace = all(e.skipWhitespace for e in self.exprs)
        else:
            self.mayReturnEmpty = True

    def streamline(self) -> ParserElement:
        super().streamline()
        if self.exprs:
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.saveAsList = any(e.saveAsList for e in self.exprs)
            self.skipWhitespace = all(
                e.skipWhitespace and not isinstance(e, White) for e in self.exprs
            )
        else:
            self.saveAsList = False
        return self

    def parseImpl(self, instring, loc, doActions=True):
        maxExcLoc = -1
        maxException = None
        matches = []
        fatals = []
        if all(e.callPreparse for e in self.exprs):
            loc = self.preParse(instring, loc)
        for e in self.exprs:
            try:
                loc2 = e.try_parse(instring, loc, raise_fatal=True)
            except ParseFatalException as pfe:
                pfe.__traceback__ = None
                pfe.parserElement = e
                fatals.append(pfe)
                maxException = None
                maxExcLoc = -1
            except ParseException as err:
                if not fatals:
                    err.__traceback__ = None
                    if err.loc > maxExcLoc:
                        maxException = err
                        maxExcLoc = err.loc
            except IndexError:
                if len(instring) > maxExcLoc:
                    maxException = ParseException(
                        instring, len(instring), e.errmsg, self
                    )
                    maxExcLoc = len(instring)
            else:
                # save match among all matches, to retry longest to shortest
                matches.append((loc2, e))

        if matches:
            # re-evaluate all matches in descending order of length of match, in case attached actions
            # might change whether or how much they match of the input.
            matches.sort(key=itemgetter(0), reverse=True)

            if not doActions:
                # no further conditions or parse actions to change the selection of
                # alternative, so the first match will be the best match
                best_expr = matches[0][1]
                return best_expr._parse(instring, loc, doActions)

            longest = -1, None
            for loc1, expr1 in matches:
                if loc1 <= longest[0]:
                    # already have a longer match than this one will deliver, we are done
                    return longest

                try:
                    loc2, toks = expr1._parse(instring, loc, doActions)
                except ParseException as err:
                    err.__traceback__ = None
                    if err.loc > maxExcLoc:
                        maxException = err
                        maxExcLoc = err.loc
                else:
                    if loc2 >= loc1:
                        return loc2, toks
                    # didn't match as much as before
                    elif loc2 > longest[0]:
                        longest = loc2, toks

            if longest != (-1, None):
                return longest

        if fatals:
            if len(fatals) > 1:
                fatals.sort(key=lambda e: -e.loc)
                if fatals[0].loc == fatals[1].loc:
                    fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement))))
            max_fatal = fatals[0]
            raise max_fatal

        if maxException is not None:
            maxException.msg = self.errmsg
            raise maxException
        else:
            raise ParseException(
                instring, loc, "no defined alternatives to match", self
            )

    def __ixor__(self, other):
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        return self.append(other)  # Or([self, other])

    def _generateDefaultName(self):
        return "{" + " ^ ".join(str(e) for e in self.exprs) + "}"

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_multiple_tokens_in_named_alternation
            and Diagnostics.warn_multiple_tokens_in_named_alternation
            not in self.suppress_warnings_
        ):
            if any(
                isinstance(e, And)
                and Diagnostics.warn_multiple_tokens_in_named_alternation
                not in e.suppress_warnings_
                for e in self.exprs
            ):
                warnings.warn(
                    "{}: setting results name {!r} on {} expression "
                    "will return a list of all parsed tokens in an And alternative, "
                    "in prior versions only the first token was returned; enclose "
                    "contained argument in Group".format(
                        "warn_multiple_tokens_in_named_alternation",
                        name,
                        type(self).__name__,
                    ),
                    stacklevel=3,
                )

        return super()._setResultsName(name, listAllMatches)


class MatchFirst(ParseExpression):
    """Requires that at least one :class:`ParseExpression` is found. If
    more than one expression matches, the first one listed is the one that will
    match. May be constructed using the ``'|'`` operator.

    Example::

        # construct MatchFirst using '|' operator

        # watch the order of expressions to match
        number = Word(nums) | Combine(Word(nums) + '.' + Word(nums))
        print(number.search_string("123 3.1416 789")) #  Fail! -> [['123'], ['3'], ['1416'], ['789']]

        # put more selective expression first
        number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums)
        print(number.search_string("123 3.1416 789")) #  Better -> [['123'], ['3.1416'], ['789']]
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.skipWhitespace = all(e.skipWhitespace for e in self.exprs)
        else:
            self.mayReturnEmpty = True

    def streamline(self) -> ParserElement:
        if self.streamlined:
            return self

        super().streamline()
        if self.exprs:
            self.saveAsList = any(e.saveAsList for e in self.exprs)
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.skipWhitespace = all(
                e.skipWhitespace and not isinstance(e, White) for e in self.exprs
            )
        else:
            self.saveAsList = False
            self.mayReturnEmpty = True
        return self

    def parseImpl(self, instring, loc, doActions=True):
        maxExcLoc = -1
        maxException = None

        for e in self.exprs:
            try:
                return e._parse(
                    instring,
                    loc,
                    doActions,
                )
            except ParseFatalException as pfe:
                pfe.__traceback__ = None
                pfe.parserElement = e
                raise
            except ParseException as err:
                if err.loc > maxExcLoc:
                    maxException = err
                    maxExcLoc = err.loc
            except IndexError:
                if len(instring) > maxExcLoc:
                    maxException = ParseException(
                        instring, len(instring), e.errmsg, self
                    )
                    maxExcLoc = len(instring)

        if maxException is not None:
            maxException.msg = self.errmsg
            raise maxException
        else:
            raise ParseException(
                instring, loc, "no defined alternatives to match", self
            )

    def __ior__(self, other):
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        return self.append(other)  # MatchFirst([self, other])

    def _generateDefaultName(self):
        return "{" + " | ".join(str(e) for e in self.exprs) + "}"

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_multiple_tokens_in_named_alternation
            and Diagnostics.warn_multiple_tokens_in_named_alternation
            not in self.suppress_warnings_
        ):
            if any(
                isinstance(e, And)
                and Diagnostics.warn_multiple_tokens_in_named_alternation
                not in e.suppress_warnings_
                for e in self.exprs
            ):
                warnings.warn(
                    "{}: setting results name {!r} on {} expression "
                    "will return a list of all parsed tokens in an And alternative, "
                    "in prior versions only the first token was returned; enclose "
                    "contained argument in Group".format(
                        "warn_multiple_tokens_in_named_alternation",
                        name,
                        type(self).__name__,
                    ),
                    stacklevel=3,
                )

        return super()._setResultsName(name, listAllMatches)


class Each(ParseExpression):
    """Requires all given :class:`ParseExpression` s to be found, but in
    any order. Expressions may be separated by whitespace.

    May be constructed using the ``'&'`` operator.

    Example::

        color = one_of("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN")
        shape_type = one_of("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON")
        integer = Word(nums)
        shape_attr = "shape:" + shape_type("shape")
        posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn")
        color_attr = "color:" + color("color")
        size_attr = "size:" + integer("size")

        # use Each (using operator '&') to accept attributes in any order
        # (shape and posn are required, color and size are optional)
        shape_spec = shape_attr & posn_attr & Opt(color_attr) & Opt(size_attr)

        shape_spec.run_tests('''
            shape: SQUARE color: BLACK posn: 100, 120
            shape: CIRCLE size: 50 color: BLUE posn: 50,80
            color:GREEN size:20 shape:TRIANGLE posn:20,40
            '''
            )

    prints::

        shape: SQUARE color: BLACK posn: 100, 120
        ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']]
        - color: BLACK
        - posn: ['100', ',', '120']
          - x: 100
          - y: 120
        - shape: SQUARE


        shape: CIRCLE size: 50 color: BLUE posn: 50,80
        ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']]
        - color: BLUE
        - posn: ['50', ',', '80']
          - x: 50
          - y: 80
        - shape: CIRCLE
        - size: 50


        color: GREEN size: 20 shape: TRIANGLE posn: 20,40
        ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']]
        - color: GREEN
        - posn: ['20', ',', '40']
          - x: 20
          - y: 40
        - shape: TRIANGLE
        - size: 20
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True):
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
        else:
            self.mayReturnEmpty = True
        self.skipWhitespace = True
        self.initExprGroups = True
        self.saveAsList = True

    def streamline(self) -> ParserElement:
        super().streamline()
        if self.exprs:
            self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
        else:
            self.mayReturnEmpty = True
        return self

    def parseImpl(self, instring, loc, doActions=True):
        if self.initExprGroups:
            self.opt1map = dict(
                (id(e.expr), e) for e in self.exprs if isinstance(e, Opt)
            )
            opt1 = [e.expr for e in self.exprs if isinstance(e, Opt)]
            opt2 = [
                e
                for e in self.exprs
                if e.mayReturnEmpty and not isinstance(e, (Opt, Regex, ZeroOrMore))
            ]
            self.optionals = opt1 + opt2
            self.multioptionals = [
                e.expr.set_results_name(e.resultsName, list_all_matches=True)
                for e in self.exprs
                if isinstance(e, _MultipleMatch)
            ]
            self.multirequired = [
                e.expr.set_results_name(e.resultsName, list_all_matches=True)
                for e in self.exprs
                if isinstance(e, OneOrMore)
            ]
            self.required = [
                e for e in self.exprs if not isinstance(e, (Opt, ZeroOrMore, OneOrMore))
            ]
            self.required += self.multirequired
            self.initExprGroups = False

        tmpLoc = loc
        tmpReqd = self.required[:]
        tmpOpt = self.optionals[:]
        multis = self.multioptionals[:]
        matchOrder = []

        keepMatching = True
        failed = []
        fatals = []
        while keepMatching:
            tmpExprs = tmpReqd + tmpOpt + multis
            failed.clear()
            fatals.clear()
            for e in tmpExprs:
                try:
                    tmpLoc = e.try_parse(instring, tmpLoc, raise_fatal=True)
                except ParseFatalException as pfe:
                    pfe.__traceback__ = None
                    pfe.parserElement = e
                    fatals.append(pfe)
                    failed.append(e)
                except ParseException:
                    failed.append(e)
                else:
                    matchOrder.append(self.opt1map.get(id(e), e))
                    if e in tmpReqd:
                        tmpReqd.remove(e)
                    elif e in tmpOpt:
                        tmpOpt.remove(e)
            if len(failed) == len(tmpExprs):
                keepMatching = False

        # look for any ParseFatalExceptions
        if fatals:
            if len(fatals) > 1:
                fatals.sort(key=lambda e: -e.loc)
                if fatals[0].loc == fatals[1].loc:
                    fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement))))
            max_fatal = fatals[0]
            raise max_fatal

        if tmpReqd:
            missing = ", ".join([str(e) for e in tmpReqd])
            raise ParseException(
                instring,
                loc,
                "Missing one or more required elements ({})".format(missing),
            )

        # add any unmatched Opts, in case they have default values defined
        matchOrder += [e for e in self.exprs if isinstance(e, Opt) and e.expr in tmpOpt]

        total_results = ParseResults([])
        for e in matchOrder:
            loc, results = e._parse(instring, loc, doActions)
            total_results += results

        return loc, total_results

    def _generateDefaultName(self):
        return "{" + " & ".join(str(e) for e in self.exprs) + "}"


class ParseElementEnhance(ParserElement):
    """Abstract subclass of :class:`ParserElement`, for combining and
    post-processing parsed tokens.
    """

    def __init__(self, expr: Union[ParserElement, str], savelist: bool = False):
        super().__init__(savelist)
        if isinstance(expr, str_type):
            if issubclass(self._literalStringClass, Token):
                expr = self._literalStringClass(expr)
            elif issubclass(type(self), self._literalStringClass):
                expr = Literal(expr)
            else:
                expr = self._literalStringClass(Literal(expr))
        self.expr = expr
        if expr is not None:
            self.mayIndexError = expr.mayIndexError
            self.mayReturnEmpty = expr.mayReturnEmpty
            self.set_whitespace_chars(
                expr.whiteChars, copy_defaults=expr.copyDefaultWhiteChars
            )
            self.skipWhitespace = expr.skipWhitespace
            self.saveAsList = expr.saveAsList
            self.callPreparse = expr.callPreparse
            self.ignoreExprs.extend(expr.ignoreExprs)

    def recurse(self) -> Sequence[ParserElement]:
        return [self.expr] if self.expr is not None else []

    def parseImpl(self, instring, loc, doActions=True):
        if self.expr is not None:
            return self.expr._parse(instring, loc, doActions, callPreParse=False)
        else:
            raise ParseException(instring, loc, "No expression defined", self)

    def leave_whitespace(self, recursive: bool = True) -> ParserElement:
        super().leave_whitespace(recursive)

        if recursive:
            self.expr = self.expr.copy()
            if self.expr is not None:
                self.expr.leave_whitespace(recursive)
        return self

    def ignore_whitespace(self, recursive: bool = True) -> ParserElement:
        super().ignore_whitespace(recursive)

        if recursive:
            self.expr = self.expr.copy()
            if self.expr is not None:
                self.expr.ignore_whitespace(recursive)
        return self

    def ignore(self, other) -> ParserElement:
        if isinstance(other, Suppress):
            if other not in self.ignoreExprs:
                super().ignore(other)
                if self.expr is not None:
                    self.expr.ignore(self.ignoreExprs[-1])
        else:
            super().ignore(other)
            if self.expr is not None:
                self.expr.ignore(self.ignoreExprs[-1])
        return self

    def streamline(self) -> ParserElement:
        super().streamline()
        if self.expr is not None:
            self.expr.streamline()
        return self

    def _checkRecursion(self, parseElementList):
        if self in parseElementList:
            raise RecursiveGrammarException(parseElementList + [self])
        subRecCheckList = parseElementList[:] + [self]
        if self.expr is not None:
            self.expr._checkRecursion(subRecCheckList)

    def validate(self, validateTrace=None) -> None:
        if validateTrace is None:
            validateTrace = []
        tmp = validateTrace[:] + [self]
        if self.expr is not None:
            self.expr.validate(tmp)
        self._checkRecursion([])

    def _generateDefaultName(self):
        return "{}:({})".format(self.__class__.__name__, str(self.expr))

    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class IndentedBlock(ParseElementEnhance):
    """
    Expression to match one or more expressions at a given indentation level.
    Useful for parsing text where structure is implied by indentation (like Python source code).
    """

    class _Indent(Empty):
        def __init__(self, ref_col: int):
            super().__init__()
            self.errmsg = "expected indent at column {}".format(ref_col)
            self.add_condition(lambda s, l, t: col(l, s) == ref_col)

    class _IndentGreater(Empty):
        def __init__(self, ref_col: int):
            super().__init__()
            self.errmsg = "expected indent at column greater than {}".format(ref_col)
            self.add_condition(lambda s, l, t: col(l, s) > ref_col)

    def __init__(
        self, expr: ParserElement, *, recursive: bool = False, grouped: bool = True
    ):
        super().__init__(expr, savelist=True)
        # if recursive:
        #     raise NotImplementedError("IndentedBlock with recursive is not implemented")
        self._recursive = recursive
        self._grouped = grouped
        self.parent_anchor = 1

    def parseImpl(self, instring, loc, doActions=True):
        # advance parse position to non-whitespace by using an Empty()
        # this should be the column to be used for all subsequent indented lines
        anchor_loc = Empty().preParse(instring, loc)

        # see if self.expr matches at the current location - if not it will raise an exception
        # and no further work is necessary
        self.expr.try_parse(instring, anchor_loc, doActions)

        indent_col = col(anchor_loc, instring)
        peer_detect_expr = self._Indent(indent_col)

        inner_expr = Empty() + peer_detect_expr + self.expr
        if self._recursive:
            sub_indent = self._IndentGreater(indent_col)
            nested_block = IndentedBlock(
                self.expr, recursive=self._recursive, grouped=self._grouped
            )
            nested_block.set_debug(self.debug)
            nested_block.parent_anchor = indent_col
            inner_expr += Opt(sub_indent + nested_block)

        inner_expr.set_name(f"inner {hex(id(inner_expr))[-4:].upper()}@{indent_col}")
        block = OneOrMore(inner_expr)

        trailing_undent = self._Indent(self.parent_anchor) | StringEnd()

        if self._grouped:
            wrapper = Group
        else:
            wrapper = lambda expr: expr
        return (wrapper(block) + Optional(trailing_undent)).parseImpl(
            instring, anchor_loc, doActions
        )


class AtStringStart(ParseElementEnhance):
    """Matches if expression matches at the beginning of the parse
    string::

        AtStringStart(Word(nums)).parse_string("123")
        # prints ["123"]

        AtStringStart(Word(nums)).parse_string("    123")
        # raises ParseException
    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        self.callPreparse = False

    def parseImpl(self, instring, loc, doActions=True):
        if loc != 0:
            raise ParseException(instring, loc, "not found at string start")
        return super().parseImpl(instring, loc, doActions)


class AtLineStart(ParseElementEnhance):
    r"""Matches if an expression matches at the beginning of a line within
    the parse string

    Example::

        test = '''\
        AAA this line
        AAA and this line
          AAA but not this one
        B AAA and definitely not this one
        '''

        for t in (AtLineStart('AAA') + restOfLine).search_string(test):
            print(t)

    prints::

        ['AAA', ' this line']
        ['AAA', ' and this line']

    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        self.callPreparse = False

    def parseImpl(self, instring, loc, doActions=True):
        if col(loc, instring) != 1:
            raise ParseException(instring, loc, "not found at line start")
        return super().parseImpl(instring, loc, doActions)


class FollowedBy(ParseElementEnhance):
    """Lookahead matching of the given parse expression.
    ``FollowedBy`` does *not* advance the parsing position within
    the input string, it only verifies that the specified parse
    expression matches at the current position.  ``FollowedBy``
    always returns a null token list. If any results names are defined
    in the lookahead expression, those *will* be returned for access by
    name.

    Example::

        # use FollowedBy to match a label only if it is followed by a ':'
        data_word = Word(alphas)
        label = data_word + FollowedBy(':')
        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))

        attr_expr[1, ...].parse_string("shape: SQUARE color: BLACK posn: upper left").pprint()

    prints::

        [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']]
    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        self.mayReturnEmpty = True

    def parseImpl(self, instring, loc, doActions=True):
        # by using self._expr.parse and deleting the contents of the returned ParseResults list
        # we keep any named results that were defined in the FollowedBy expression
        _, ret = self.expr._parse(instring, loc, doActions=doActions)
        del ret[:]

        return loc, ret


class PrecededBy(ParseElementEnhance):
    """Lookbehind matching of the given parse expression.
    ``PrecededBy`` does not advance the parsing position within the
    input string, it only verifies that the specified parse expression
    matches prior to the current position.  ``PrecededBy`` always
    returns a null token list, but if a results name is defined on the
    given expression, it is returned.

    Parameters:

    - expr - expression that must match prior to the current parse
      location
    - retreat - (default= ``None``) - (int) maximum number of characters
      to lookbehind prior to the current parse location

    If the lookbehind expression is a string, :class:`Literal`,
    :class:`Keyword`, or a :class:`Word` or :class:`CharsNotIn`
    with a specified exact or maximum length, then the retreat
    parameter is not required. Otherwise, retreat must be specified to
    give a maximum number of characters to look back from
    the current parse position for a lookbehind match.

    Example::

        # VB-style variable names with type prefixes
        int_var = PrecededBy("#") + pyparsing_common.identifier
        str_var = PrecededBy("$") + pyparsing_common.identifier

    """

    def __init__(
        self, expr: Union[ParserElement, str], retreat: typing.Optional[int] = None
    ):
        super().__init__(expr)
        self.expr = self.expr().leave_whitespace()
        self.mayReturnEmpty = True
        self.mayIndexError = False
        self.exact = False
        if isinstance(expr, str_type):
            retreat = len(expr)
            self.exact = True
        elif isinstance(expr, (Literal, Keyword)):
            retreat = expr.matchLen
            self.exact = True
        elif isinstance(expr, (Word, CharsNotIn)) and expr.maxLen != _MAX_INT:
            retreat = expr.maxLen
            self.exact = True
        elif isinstance(expr, PositionToken):
            retreat = 0
            self.exact = True
        self.retreat = retreat
        self.errmsg = "not preceded by " + str(expr)
        self.skipWhitespace = False
        self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None)))

    def parseImpl(self, instring, loc=0, doActions=True):
        if self.exact:
            if loc < self.retreat:
                raise ParseException(instring, loc, self.errmsg)
            start = loc - self.retreat
            _, ret = self.expr._parse(instring, start)
        else:
            # retreat specified a maximum lookbehind window, iterate
            test_expr = self.expr + StringEnd()
            instring_slice = instring[max(0, loc - self.retreat) : loc]
            last_expr = ParseException(instring, loc, self.errmsg)
            for offset in range(1, min(loc, self.retreat + 1) + 1):
                try:
                    # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:]))
                    _, ret = test_expr._parse(
                        instring_slice, len(instring_slice) - offset
                    )
                except ParseBaseException as pbe:
                    last_expr = pbe
                else:
                    break
            else:
                raise last_expr
        return loc, ret


class Located(ParseElementEnhance):
    """
    Decorates a returned token with its starting and ending
    locations in the input string.

    This helper adds the following results names:

    - ``locn_start`` - location where matched expression begins
    - ``locn_end`` - location where matched expression ends
    - ``value`` - the actual parsed results

    Be careful if the input text contains ``<TAB>`` characters, you
    may want to call :class:`ParserElement.parse_with_tabs`

    Example::

        wd = Word(alphas)
        for match in Located(wd).search_string("ljsdf123lksdjjf123lkkjj1222"):
            print(match)

    prints::

        [0, ['ljsdf'], 5]
        [8, ['lksdjjf'], 15]
        [18, ['lkkjj'], 23]

    """

    def parseImpl(self, instring, loc, doActions=True):
        start = loc
        loc, tokens = self.expr._parse(instring, start, doActions, callPreParse=False)
        ret_tokens = ParseResults([start, tokens, loc])
        ret_tokens["locn_start"] = start
        ret_tokens["value"] = tokens
        ret_tokens["locn_end"] = loc
        if self.resultsName:
            # must return as a list, so that the name will be attached to the complete group
            return loc, [ret_tokens]
        else:
            return loc, ret_tokens


class NotAny(ParseElementEnhance):
    """
    Lookahead to disallow matching with the given parse expression.
    ``NotAny`` does *not* advance the parsing position within the
    input string, it only verifies that the specified parse expression
    does *not* match at the current position.  Also, ``NotAny`` does
    *not* skip over leading whitespace. ``NotAny`` always returns
    a null token list.  May be constructed using the ``'~'`` operator.

    Example::

        AND, OR, NOT = map(CaselessKeyword, "AND OR NOT".split())

        # take care not to mistake keywords for identifiers
        ident = ~(AND | OR | NOT) + Word(alphas)
        boolean_term = Opt(NOT) + ident

        # very crude boolean expression - to support parenthesis groups and
        # operation hierarchy, use infix_notation
        boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...]

        # integers that are followed by "." are actually floats
        integer = Word(nums) + ~Char(".")
    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        # do NOT use self.leave_whitespace(), don't want to propagate to exprs
        # self.leave_whitespace()
        self.skipWhitespace = False

        self.mayReturnEmpty = True
        self.errmsg = "Found unwanted token, " + str(self.expr)

    def parseImpl(self, instring, loc, doActions=True):
        if self.expr.can_parse_next(instring, loc):
            raise ParseException(instring, loc, self.errmsg, self)
        return loc, []

    def _generateDefaultName(self):
        return "~{" + str(self.expr) + "}"


class _MultipleMatch(ParseElementEnhance):
    def __init__(
        self,
        expr: ParserElement,
        stop_on: typing.Optional[Union[ParserElement, str]] = None,
        *,
        stopOn: typing.Optional[Union[ParserElement, str]] = None,
    ):
        super().__init__(expr)
        stopOn = stopOn or stop_on
        self.saveAsList = True
        ender = stopOn
        if isinstance(ender, str_type):
            ender = self._literalStringClass(ender)
        self.stopOn(ender)

    def stopOn(self, ender) -> ParserElement:
        if isinstance(ender, str_type):
            ender = self._literalStringClass(ender)
        self.not_ender = ~ender if ender is not None else None
        return self

    def parseImpl(self, instring, loc, doActions=True):
        self_expr_parse = self.expr._parse
        self_skip_ignorables = self._skipIgnorables
        check_ender = self.not_ender is not None
        if check_ender:
            try_not_ender = self.not_ender.tryParse

        # must be at least one (but first see if we are the stopOn sentinel;
        # if so, fail)
        if check_ender:
            try_not_ender(instring, loc)
        loc, tokens = self_expr_parse(instring, loc, doActions)
        try:
            hasIgnoreExprs = not not self.ignoreExprs
            while 1:
                if check_ender:
                    try_not_ender(instring, loc)
                if hasIgnoreExprs:
                    preloc = self_skip_ignorables(instring, loc)
                else:
                    preloc = loc
                loc, tmptokens = self_expr_parse(instring, preloc, doActions)
                if tmptokens or tmptokens.haskeys():
                    tokens += tmptokens
        except (ParseException, IndexError):
            pass

        return loc, tokens

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_ungrouped_named_tokens_in_collection
            and Diagnostics.warn_ungrouped_named_tokens_in_collection
            not in self.suppress_warnings_
        ):
            for e in [self.expr] + self.expr.recurse():
                if (
                    isinstance(e, ParserElement)
                    and e.resultsName
                    and Diagnostics.warn_ungrouped_named_tokens_in_collection
                    not in e.suppress_warnings_
                ):
                    warnings.warn(
                        "{}: setting results name {!r} on {} expression "
                        "collides with {!r} on contained expression".format(
                            "warn_ungrouped_named_tokens_in_collection",
                            name,
                            type(self).__name__,
                            e.resultsName,
                        ),
                        stacklevel=3,
                    )

        return super()._setResultsName(name, listAllMatches)


class OneOrMore(_MultipleMatch):
    """
    Repetition of one or more of the given expression.

    Parameters:
    - expr - expression that must match one or more times
    - stop_on - (default= ``None``) - expression for a terminating sentinel
         (only required if the sentinel would ordinarily match the repetition
         expression)

    Example::

        data_word = Word(alphas)
        label = data_word + FollowedBy(':')
        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).set_parse_action(' '.join))

        text = "shape: SQUARE posn: upper left color: BLACK"
        attr_expr[1, ...].parse_string(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]

        # use stop_on attribute for OneOrMore to avoid reading label string as part of the data
        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
        OneOrMore(attr_expr).parse_string(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']]

        # could also be written as
        (attr_expr * (1,)).parse_string(text).pprint()
    """

    def _generateDefaultName(self):
        return "{" + str(self.expr) + "}..."


class ZeroOrMore(_MultipleMatch):
    """
    Optional repetition of zero or more of the given expression.

    Parameters:
    - ``expr`` - expression that must match zero or more times
    - ``stop_on`` - expression for a terminating sentinel
      (only required if the sentinel would ordinarily match the repetition
      expression) - (default= ``None``)

    Example: similar to :class:`OneOrMore`
    """

    def __init__(
        self,
        expr: ParserElement,
        stop_on: typing.Optional[Union[ParserElement, str]] = None,
        *,
        stopOn: typing.Optional[Union[ParserElement, str]] = None,
    ):
        super().__init__(expr, stopOn=stopOn or stop_on)
        self.mayReturnEmpty = True

    def parseImpl(self, instring, loc, doActions=True):
        try:
            return super().parseImpl(instring, loc, doActions)
        except (ParseException, IndexError):
            return loc, ParseResults([], name=self.resultsName)

    def _generateDefaultName(self):
        return "[" + str(self.expr) + "]..."


class _NullToken:
    def __bool__(self):
        return False

    def __str__(self):
        return ""


class Opt(ParseElementEnhance):
    """
    Optional matching of the given expression.

    Parameters:
    - ``expr`` - expression that must match zero or more times
    - ``default`` (optional) - value to be returned if the optional expression is not found.

    Example::

        # US postal code can be a 5-digit zip, plus optional 4-digit qualifier
        zip = Combine(Word(nums, exact=5) + Opt('-' + Word(nums, exact=4)))
        zip.run_tests('''
            # traditional ZIP code
            12345

            # ZIP+4 form
            12101-0001

            # invalid ZIP
            98765-
            ''')

    prints::

        # traditional ZIP code
        12345
        ['12345']

        # ZIP+4 form
        12101-0001
        ['12101-0001']

        # invalid ZIP
        98765-
             ^
        FAIL: Expected end of text (at char 5), (line:1, col:6)
    """

    __optionalNotMatched = _NullToken()

    def __init__(
        self, expr: Union[ParserElement, str], default: Any = __optionalNotMatched
    ):
        super().__init__(expr, savelist=False)
        self.saveAsList = self.expr.saveAsList
        self.defaultValue = default
        self.mayReturnEmpty = True

    def parseImpl(self, instring, loc, doActions=True):
        self_expr = self.expr
        try:
            loc, tokens = self_expr._parse(instring, loc, doActions, callPreParse=False)
        except (ParseException, IndexError):
            default_value = self.defaultValue
            if default_value is not self.__optionalNotMatched:
                if self_expr.resultsName:
                    tokens = ParseResults([default_value])
                    tokens[self_expr.resultsName] = default_value
                else:
                    tokens = [default_value]
            else:
                tokens = []
        return loc, tokens

    def _generateDefaultName(self):
        inner = str(self.expr)
        # strip off redundant inner {}'s
        while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}":
            inner = inner[1:-1]
        return "[" + inner + "]"


Optional = Opt


class SkipTo(ParseElementEnhance):
    """
    Token for skipping over all undefined text until the matched
    expression is found.

    Parameters:
    - ``expr`` - target expression marking the end of the data to be skipped
    - ``include`` - if ``True``, the target expression is also parsed
      (the skipped text and target expression are returned as a 2-element
      list) (default= ``False``).
    - ``ignore`` - (default= ``None``) used to define grammars (typically quoted strings and
      comments) that might contain false matches to the target expression
    - ``fail_on`` - (default= ``None``) define expressions that are not allowed to be
      included in the skipped test; if found before the target expression is found,
      the :class:`SkipTo` is not a match

    Example::

        report = '''
            Outstanding Issues Report - 1 Jan 2000

               # | Severity | Description                               |  Days Open
            -----+----------+-------------------------------------------+-----------
             101 | Critical | Intermittent system crash                 |          6
              94 | Cosmetic | Spelling error on Login ('log|n')         |         14
              79 | Minor    | System slow when running too many reports |         47
            '''
        integer = Word(nums)
        SEP = Suppress('|')
        # use SkipTo to simply match everything up until the next SEP
        # - ignore quoted strings, so that a '|' character inside a quoted string does not match
        # - parse action will call token.strip() for each matched token, i.e., the description body
        string_data = SkipTo(SEP, ignore=quoted_string)
        string_data.set_parse_action(token_map(str.strip))
        ticket_expr = (integer("issue_num") + SEP
                      + string_data("sev") + SEP
                      + string_data("desc") + SEP
                      + integer("days_open"))

        for tkt in ticket_expr.search_string(report):
            print tkt.dump()

    prints::

        ['101', 'Critical', 'Intermittent system crash', '6']
        - days_open: '6'
        - desc: 'Intermittent system crash'
        - issue_num: '101'
        - sev: 'Critical'
        ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14']
        - days_open: '14'
        - desc: "Spelling error on Login ('log|n')"
        - issue_num: '94'
        - sev: 'Cosmetic'
        ['79', 'Minor', 'System slow when running too many reports', '47']
        - days_open: '47'
        - desc: 'System slow when running too many reports'
        - issue_num: '79'
        - sev: 'Minor'
    """

    def __init__(
        self,
        other: Union[ParserElement, str],
        include: bool = False,
        ignore: bool = None,
        fail_on: typing.Optional[Union[ParserElement, str]] = None,
        *,
        failOn: Union[ParserElement, str] = None,
    ):
        super().__init__(other)
        failOn = failOn or fail_on
        self.ignoreExpr = ignore
        self.mayReturnEmpty = True
        self.mayIndexError = False
        self.includeMatch = include
        self.saveAsList = False
        if isinstance(failOn, str_type):
            self.failOn = self._literalStringClass(failOn)
        else:
            self.failOn = failOn
        self.errmsg = "No match found for " + str(self.expr)

    def parseImpl(self, instring, loc, doActions=True):
        startloc = loc
        instrlen = len(instring)
        self_expr_parse = self.expr._parse
        self_failOn_canParseNext = (
            self.failOn.canParseNext if self.failOn is not None else None
        )
        self_ignoreExpr_tryParse = (
            self.ignoreExpr.tryParse if self.ignoreExpr is not None else None
        )

        tmploc = loc
        while tmploc <= instrlen:
            if self_failOn_canParseNext is not None:
                # break if failOn expression matches
                if self_failOn_canParseNext(instring, tmploc):
                    break

            if self_ignoreExpr_tryParse is not None:
                # advance past ignore expressions
                while 1:
                    try:
                        tmploc = self_ignoreExpr_tryParse(instring, tmploc)
                    except ParseBaseException:
                        break

            try:
                self_expr_parse(instring, tmploc, doActions=False, callPreParse=False)
            except (ParseException, IndexError):
                # no match, advance loc in string
                tmploc += 1
            else:
                # matched skipto expr, done
                break

        else:
            # ran off the end of the input string without matching skipto expr, fail
            raise ParseException(instring, loc, self.errmsg, self)

        # build up return values
        loc = tmploc
        skiptext = instring[startloc:loc]
        skipresult = ParseResults(skiptext)

        if self.includeMatch:
            loc, mat = self_expr_parse(instring, loc, doActions, callPreParse=False)
            skipresult += mat

        return loc, skipresult


class Forward(ParseElementEnhance):
    """
    Forward declaration of an expression to be defined later -
    used for recursive grammars, such as algebraic infix notation.
    When the expression is known, it is assigned to the ``Forward``
    variable using the ``'<<'`` operator.

    Note: take care when assigning to ``Forward`` not to overlook
    precedence of operators.

    Specifically, ``'|'`` has a lower precedence than ``'<<'``, so that::

        fwd_expr << a | b | c

    will actually be evaluated as::

        (fwd_expr << a) | b | c

    thereby leaving b and c out as parseable alternatives.  It is recommended that you
    explicitly group the values inserted into the ``Forward``::

        fwd_expr << (a | b | c)

    Converting to use the ``'<<='`` operator instead will avoid this problem.

    See :class:`ParseResults.pprint` for an example of a recursive
    parser created using ``Forward``.
    """

    def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None):
        self.caller_frame = traceback.extract_stack(limit=2)[0]
        super().__init__(other, savelist=False)
        self.lshift_line = None

    def __lshift__(self, other):
        if hasattr(self, "caller_frame"):
            del self.caller_frame
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        self.expr = other
        self.mayIndexError = self.expr.mayIndexError
        self.mayReturnEmpty = self.expr.mayReturnEmpty
        self.set_whitespace_chars(
            self.expr.whiteChars, copy_defaults=self.expr.copyDefaultWhiteChars
        )
        self.skipWhitespace = self.expr.skipWhitespace
        self.saveAsList = self.expr.saveAsList
        self.ignoreExprs.extend(self.expr.ignoreExprs)
        self.lshift_line = traceback.extract_stack(limit=2)[-2]
        return self

    def __ilshift__(self, other):
        return self << other

    def __or__(self, other):
        caller_line = traceback.extract_stack(limit=2)[-2]
        if (
            __diag__.warn_on_match_first_with_lshift_operator
            and caller_line == self.lshift_line
            and Diagnostics.warn_on_match_first_with_lshift_operator
            not in self.suppress_warnings_
        ):
            warnings.warn(
                "using '<<' operator with '|' is probably an error, use '<<='",
                stacklevel=2,
            )
        ret = super().__or__(other)
        return ret

    def __del__(self):
        # see if we are getting dropped because of '=' reassignment of var instead of '<<=' or '<<'
        if (
            self.expr is None
            and __diag__.warn_on_assignment_to_Forward
            and Diagnostics.warn_on_assignment_to_Forward not in self.suppress_warnings_
        ):
            warnings.warn_explicit(
                "Forward defined here but no expression attached later using '<<=' or '<<'",
                UserWarning,
                filename=self.caller_frame.filename,
                lineno=self.caller_frame.lineno,
            )

    def parseImpl(self, instring, loc, doActions=True):
        if (
            self.expr is None
            and __diag__.warn_on_parse_using_empty_Forward
            and Diagnostics.warn_on_parse_using_empty_Forward
            not in self.suppress_warnings_
        ):
            # walk stack until parse_string, scan_string, search_string, or transform_string is found
            parse_fns = [
                "parse_string",
                "scan_string",
                "search_string",
                "transform_string",
            ]
            tb = traceback.extract_stack(limit=200)
            for i, frm in enumerate(reversed(tb), start=1):
                if frm.name in parse_fns:
                    stacklevel = i + 1
                    break
            else:
                stacklevel = 2
            warnings.warn(
                "Forward expression was never assigned a value, will not parse any input",
                stacklevel=stacklevel,
            )
        if not ParserElement._left_recursion_enabled:
            return super().parseImpl(instring, loc, doActions)
        # ## Bounded Recursion algorithm ##
        # Recursion only needs to be processed at ``Forward`` elements, since they are
        # the only ones that can actually refer to themselves. The general idea is
        # to handle recursion stepwise: We start at no recursion, then recurse once,
        # recurse twice, ..., until more recursion offers no benefit (we hit the bound).
        #
        # The "trick" here is that each ``Forward`` gets evaluated in two contexts
        # - to *match* a specific recursion level, and
        # - to *search* the bounded recursion level
        # and the two run concurrently. The *search* must *match* each recursion level
        # to find the best possible match. This is handled by a memo table, which
        # provides the previous match to the next level match attempt.
        #
        # See also "Left Recursion in Parsing Expression Grammars", Medeiros et al.
        #
        # There is a complication since we not only *parse* but also *transform* via
        # actions: We do not want to run the actions too often while expanding. Thus,
        # we expand using `doActions=False` and only run `doActions=True` if the next
        # recursion level is acceptable.
        with ParserElement.recursion_lock:
            memo = ParserElement.recursion_memos
            try:
                # we are parsing at a specific recursion expansion - use it as-is
                prev_loc, prev_result = memo[loc, self, doActions]
                if isinstance(prev_result, Exception):
                    raise prev_result
                return prev_loc, prev_result.copy()
            except KeyError:
                act_key = (loc, self, True)
                peek_key = (loc, self, False)
                # we are searching for the best recursion expansion - keep on improving
                # both `doActions` cases must be tracked separately here!
                prev_loc, prev_peek = memo[peek_key] = (
                    loc - 1,
                    ParseException(
                        instring, loc, "Forward recursion without base case", self
                    ),
                )
                if doActions:
                    memo[act_key] = memo[peek_key]
                while True:
                    try:
                        new_loc, new_peek = super().parseImpl(instring, loc, False)
                    except ParseException:
                        # we failed before getting any match – do not hide the error
                        if isinstance(prev_peek, Exception):
                            raise
                        new_loc, new_peek = prev_loc, prev_peek
                    # the match did not get better: we are done
                    if new_loc <= prev_loc:
                        if doActions:
                            # replace the match for doActions=False as well,
                            # in case the action did backtrack
                            prev_loc, prev_result = memo[peek_key] = memo[act_key]
                            del memo[peek_key], memo[act_key]
                            return prev_loc, prev_result.copy()
                        del memo[peek_key]
                        return prev_loc, prev_peek.copy()
                    # the match did get better: see if we can improve further
                    else:
                        if doActions:
                            try:
                                memo[act_key] = super().parseImpl(instring, loc, True)
                            except ParseException as e:
                                memo[peek_key] = memo[act_key] = (new_loc, e)
                                raise
                        prev_loc, prev_peek = memo[peek_key] = new_loc, new_peek

    def leave_whitespace(self, recursive: bool = True) -> ParserElement:
        self.skipWhitespace = False
        return self

    def ignore_whitespace(self, recursive: bool = True) -> ParserElement:
        self.skipWhitespace = True
        return self

    def streamline(self) -> ParserElement:
        if not self.streamlined:
            self.streamlined = True
            if self.expr is not None:
                self.expr.streamline()
        return self

    def validate(self, validateTrace=None) -> None:
        if validateTrace is None:
            validateTrace = []

        if self not in validateTrace:
            tmp = validateTrace[:] + [self]
            if self.expr is not None:
                self.expr.validate(tmp)
        self._checkRecursion([])

    def _generateDefaultName(self):
        # Avoid infinite recursion by setting a temporary _defaultName
        self._defaultName = ": ..."

        # Use the string representation of main expression.
        retString = "..."
        try:
            if self.expr is not None:
                retString = str(self.expr)[:1000]
            else:
                retString = "None"
        finally:
            return self.__class__.__name__ + ": " + retString

    def copy(self) -> ParserElement:
        if self.expr is not None:
            return super().copy()
        else:
            ret = Forward()
            ret <<= self
            return ret

    def _setResultsName(self, name, list_all_matches=False):
        if (
            __diag__.warn_name_set_on_empty_Forward
            and Diagnostics.warn_name_set_on_empty_Forward
            not in self.suppress_warnings_
        ):
            if self.expr is None:
                warnings.warn(
                    "{}: setting results name {!r} on {} expression "
                    "that has no contained expression".format(
                        "warn_name_set_on_empty_Forward", name, type(self).__name__
                    ),
                    stacklevel=3,
                )

        return super()._setResultsName(name, list_all_matches)

    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class TokenConverter(ParseElementEnhance):
    """
    Abstract subclass of :class:`ParseExpression`, for converting parsed results.
    """

    def __init__(self, expr: Union[ParserElement, str], savelist=False):
        super().__init__(expr)  # , savelist)
        self.saveAsList = False


class Combine(TokenConverter):
    """Converter to concatenate all matching tokens to a single string.
    By default, the matching patterns must also be contiguous in the
    input string; this can be disabled by specifying
    ``'adjacent=False'`` in the constructor.

    Example::

        real = Word(nums) + '.' + Word(nums)
        print(real.parse_string('3.1416')) # -> ['3', '.', '1416']
        # will also erroneously match the following
        print(real.parse_string('3. 1416')) # -> ['3', '.', '1416']

        real = Combine(Word(nums) + '.' + Word(nums))
        print(real.parse_string('3.1416')) # -> ['3.1416']
        # no match when there are internal spaces
        print(real.parse_string('3. 1416')) # -> Exception: Expected W:(0123...)
    """

    def __init__(
        self,
        expr: ParserElement,
        join_string: str = "",
        adjacent: bool = True,
        *,
        joinString: typing.Optional[str] = None,
    ):
        super().__init__(expr)
        joinString = joinString if joinString is not None else join_string
        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
        if adjacent:
            self.leave_whitespace()
        self.adjacent = adjacent
        self.skipWhitespace = True
        self.joinString = joinString
        self.callPreparse = True

    def ignore(self, other) -> ParserElement:
        if self.adjacent:
            ParserElement.ignore(self, other)
        else:
            super().ignore(other)
        return self

    def postParse(self, instring, loc, tokenlist):
        retToks = tokenlist.copy()
        del retToks[:]
        retToks += ParseResults(
            ["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults
        )

        if self.resultsName and retToks.haskeys():
            return [retToks]
        else:
            return retToks


class Group(TokenConverter):
    """Converter to return the matched tokens as a list - useful for
    returning tokens of :class:`ZeroOrMore` and :class:`OneOrMore` expressions.

    The optional ``aslist`` argument when set to True will return the
    parsed tokens as a Python list instead of a pyparsing ParseResults.

    Example::

        ident = Word(alphas)
        num = Word(nums)
        term = ident | num
        func = ident + Opt(delimited_list(term))
        print(func.parse_string("fn a, b, 100"))
        # -> ['fn', 'a', 'b', '100']

        func = ident + Group(Opt(delimited_list(term)))
        print(func.parse_string("fn a, b, 100"))
        # -> ['fn', ['a', 'b', '100']]
    """

    def __init__(self, expr: ParserElement, aslist: bool = False):
        super().__init__(expr)
        self.saveAsList = True
        self._asPythonList = aslist

    def postParse(self, instring, loc, tokenlist):
        if self._asPythonList:
            return ParseResults.List(
                tokenlist.asList()
                if isinstance(tokenlist, ParseResults)
                else list(tokenlist)
            )
        else:
            return [tokenlist]


class Dict(TokenConverter):
    """Converter to return a repetitive expression as a list, but also
    as a dictionary. Each element can also be referenced using the first
    token in the expression as its key. Useful for tabular report
    scraping when the first column can be used as a item key.

    The optional ``asdict`` argument when set to True will return the
    parsed tokens as a Python dict instead of a pyparsing ParseResults.

    Example::

        data_word = Word(alphas)
        label = data_word + FollowedBy(':')

        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))

        # print attributes as plain groups
        print(attr_expr[1, ...].parse_string(text).dump())

        # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) - Dict will auto-assign names
        result = Dict(Group(attr_expr)[1, ...]).parse_string(text)
        print(result.dump())

        # access named fields as dict entries, or output as dict
        print(result['shape'])
        print(result.as_dict())

    prints::

        ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap']
        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]
        - color: 'light blue'
        - posn: 'upper left'
        - shape: 'SQUARE'
        - texture: 'burlap'
        SQUARE
        {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'}

    See more examples at :class:`ParseResults` of accessing fields by results name.
    """

    def __init__(self, expr: ParserElement, asdict: bool = False):
        super().__init__(expr)
        self.saveAsList = True
        self._asPythonDict = asdict

    def postParse(self, instring, loc, tokenlist):
        for i, tok in enumerate(tokenlist):
            if len(tok) == 0:
                continue

            ikey = tok[0]
            if isinstance(ikey, int):
                ikey = str(ikey).strip()

            if len(tok) == 1:
                tokenlist[ikey] = _ParseResultsWithOffset("", i)

            elif len(tok) == 2 and not isinstance(tok[1], ParseResults):
                tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i)

            else:
                try:
                    dictvalue = tok.copy()  # ParseResults(i)
                except Exception:
                    exc = TypeError(
                        "could not extract dict values from parsed results"
                        " - Dict expression must contain Grouped expressions"
                    )
                    raise exc from None

                del dictvalue[0]

                if len(dictvalue) != 1 or (
                    isinstance(dictvalue, ParseResults) and dictvalue.haskeys()
                ):
                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i)
                else:
                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i)

        if self._asPythonDict:
            return [tokenlist.as_dict()] if self.resultsName else tokenlist.as_dict()
        else:
            return [tokenlist] if self.resultsName else tokenlist


class Suppress(TokenConverter):
    """Converter for ignoring the results of a parsed expression.

    Example::

        source = "a, b, c,d"
        wd = Word(alphas)
        wd_list1 = wd + (',' + wd)[...]
        print(wd_list1.parse_string(source))

        # often, delimiters that are useful during parsing are just in the
        # way afterward - use Suppress to keep them out of the parsed output
        wd_list2 = wd + (Suppress(',') + wd)[...]
        print(wd_list2.parse_string(source))

        # Skipped text (using '...') can be suppressed as well
        source = "lead in START relevant text END trailing text"
        start_marker = Keyword("START")
        end_marker = Keyword("END")
        find_body = Suppress(...) + start_marker + ... + end_marker
        print(find_body.parse_string(source)

    prints::

        ['a', ',', 'b', ',', 'c', ',', 'd']
        ['a', 'b', 'c', 'd']
        ['START', 'relevant text ', 'END']

    (See also :class:`delimited_list`.)
    """

    def __init__(self, expr: Union[ParserElement, str], savelist: bool = False):
        if expr is ...:
            expr = _PendingSkip(NoMatch())
        super().__init__(expr)

    def __add__(self, other) -> "ParserElement":
        if isinstance(self.expr, _PendingSkip):
            return Suppress(SkipTo(other)) + other
        else:
            return super().__add__(other)

    def __sub__(self, other) -> "ParserElement":
        if isinstance(self.expr, _PendingSkip):
            return Suppress(SkipTo(other)) - other
        else:
            return super().__sub__(other)

    def postParse(self, instring, loc, tokenlist):
        return []

    def suppress(self) -> ParserElement:
        return self


def trace_parse_action(f: ParseAction) -> ParseAction:
    """Decorator for debugging parse actions.

    When the parse action is called, this decorator will print
    ``">> entering method-name(line:<current_source_line>, <parse_location>, <matched_tokens>)"``.
    When the parse action completes, the decorator will print
    ``"<<"`` followed by the returned value, or any exception that the parse action raised.

    Example::

        wd = Word(alphas)

        @trace_parse_action
        def remove_duplicate_chars(tokens):
            return ''.join(sorted(set(''.join(tokens))))

        wds = wd[1, ...].set_parse_action(remove_duplicate_chars)
        print(wds.parse_string("slkdjs sld sldd sdlf sdljf"))

    prints::

        >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {}))
        <<leaving remove_duplicate_chars (ret: 'dfjkls')
        ['dfjkls']
    """
    f = _trim_arity(f)

    def z(*paArgs):
        thisFunc = f.__name__
        s, l, t = paArgs[-3:]
        if len(paArgs) > 3:
            thisFunc = paArgs[0].__class__.__name__ + "." + thisFunc
        sys.stderr.write(
            ">>entering {}(line: {!r}, {}, {!r})\n".format(thisFunc, line(l, s), l, t)
        )
        try:
            ret = f(*paArgs)
        except Exception as exc:
            sys.stderr.write("<<leaving {} (exception: {})\n".format(thisFunc, exc))
            raise
        sys.stderr.write("<<leaving {} (ret: {!r})\n".format(thisFunc, ret))
        return ret

    z.__name__ = f.__name__
    return z


# convenience constants for positional expressions
empty = Empty().set_name("empty")
line_start = LineStart().set_name("line_start")
line_end = LineEnd().set_name("line_end")
string_start = StringStart().set_name("string_start")
string_end = StringEnd().set_name("string_end")

_escapedPunc = Word(_bslash, r"\[]-*.$+^?()~ ", exact=2).set_parse_action(
    lambda s, l, t: t[0][1]
)
_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").set_parse_action(
    lambda s, l, t: chr(int(t[0].lstrip(r"\0x"), 16))
)
_escapedOctChar = Regex(r"\\0[0-7]+").set_parse_action(
    lambda s, l, t: chr(int(t[0][1:], 8))
)
_singleChar = (
    _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r"\]", exact=1)
)
_charRange = Group(_singleChar + Suppress("-") + _singleChar)
_reBracketExpr = (
    Literal("[")
    + Opt("^").set_results_name("negate")
    + Group(OneOrMore(_charRange | _singleChar)).set_results_name("body")
    + "]"
)


def srange(s: str) -> str:
    r"""Helper to easily define string ranges for use in :class:`Word`
    construction. Borrows syntax from regexp ``'[]'`` string range
    definitions::

        srange("[0-9]")   -> "0123456789"
        srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
        srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"

    The input string must be enclosed in []'s, and the returned string
    is the expanded character set joined into a single string. The
    values enclosed in the []'s may be:

    - a single character
    - an escaped character with a leading backslash (such as ``\-``
      or ``\]``)
    - an escaped hex character with a leading ``'\x'``
      (``\x21``, which is a ``'!'`` character) (``\0x##``
      is also supported for backwards compatibility)
    - an escaped octal character with a leading ``'\0'``
      (``\041``, which is a ``'!'`` character)
    - a range of any of the above, separated by a dash (``'a-z'``,
      etc.)
    - any combination of the above (``'aeiouy'``,
      ``'a-zA-Z0-9_$'``, etc.)
    """
    _expanded = (
        lambda p: p
        if not isinstance(p, ParseResults)
        else "".join(chr(c) for c in range(ord(p[0]), ord(p[1]) + 1))
    )
    try:
        return "".join(_expanded(part) for part in _reBracketExpr.parse_string(s).body)
    except Exception:
        return ""


def token_map(func, *args) -> ParseAction:
    """Helper to define a parse action by mapping a function to all
    elements of a :class:`ParseResults` list. If any additional args are passed,
    they are forwarded to the given function as additional arguments
    after the token, as in
    ``hex_integer = Word(hexnums).set_parse_action(token_map(int, 16))``,
    which will convert the parsed data to an integer using base 16.

    Example (compare the last to example in :class:`ParserElement.transform_string`::

        hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16))
        hex_ints.run_tests('''
            00 11 22 aa FF 0a 0d 1a
            ''')

        upperword = Word(alphas).set_parse_action(token_map(str.upper))
        upperword[1, ...].run_tests('''
            my kingdom for a horse
            ''')

        wd = Word(alphas).set_parse_action(token_map(str.title))
        wd[1, ...].set_parse_action(' '.join).run_tests('''
            now is the winter of our discontent made glorious summer by this sun of york
            ''')

    prints::

        00 11 22 aa FF 0a 0d 1a
        [0, 17, 34, 170, 255, 10, 13, 26]

        my kingdom for a horse
        ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE']

        now is the winter of our discontent made glorious summer by this sun of york
        ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York']
    """

    def pa(s, l, t):
        return [func(tokn, *args) for tokn in t]

    func_name = getattr(func, "__name__", getattr(func, "__class__").__name__)
    pa.__name__ = func_name

    return pa


def autoname_elements() -> None:
    """
    Utility to simplify mass-naming of parser elements, for
    generating railroad diagram with named subdiagrams.
    """
    for name, var in sys._getframe().f_back.f_locals.items():
        if isinstance(var, ParserElement) and not var.customName:
            var.set_name(name)


dbl_quoted_string = Combine(
    Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"'
).set_name("string enclosed in double quotes")

sgl_quoted_string = Combine(
    Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'"
).set_name("string enclosed in single quotes")

quoted_string = Combine(
    Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"'
    | Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'"
).set_name("quotedString using single or double quotes")

unicode_string = Combine("u" + quoted_string.copy()).set_name("unicode string literal")


alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")

# build list of built-in expressions, for future reference if a global default value
# gets updated
_builtin_exprs: List[ParserElement] = [
    v for v in vars().values() if isinstance(v, ParserElement)
]

# backward compatibility names
tokenMap = token_map
conditionAsParseAction = condition_as_parse_action
nullDebugAction = null_debug_action
sglQuotedString = sgl_quoted_string
dblQuotedString = dbl_quoted_string
quotedString = quoted_string
unicodeString = unicode_string
lineStart = line_start
lineEnd = line_end
stringStart = string_start
stringEnd = string_end
traceParseAction = trace_parse_action
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  import abc
import collections
import collections.abc
import functools
import operator
import sys
import types as _types
import typing


__all__ = [
    # Super-special typing primitives.
    'Any',
    'ClassVar',
    'Concatenate',
    'Final',
    'LiteralString',
    'ParamSpec',
    'ParamSpecArgs',
    'ParamSpecKwargs',
    'Self',
    'Type',
    'TypeVar',
    'TypeVarTuple',
    'Unpack',

    # ABCs (from collections.abc).
    'Awaitable',
    'AsyncIterator',
    'AsyncIterable',
    'Coroutine',
    'AsyncGenerator',
    'AsyncContextManager',
    'ChainMap',

    # Concrete collection types.
    'ContextManager',
    'Counter',
    'Deque',
    'DefaultDict',
    'NamedTuple',
    'OrderedDict',
    'TypedDict',

    # Structural checks, a.k.a. protocols.
    'SupportsIndex',

    # One-off things.
    'Annotated',
    'assert_never',
    'assert_type',
    'clear_overloads',
    'dataclass_transform',
    'get_overloads',
    'final',
    'get_args',
    'get_origin',
    'get_type_hints',
    'IntVar',
    'is_typeddict',
    'Literal',
    'NewType',
    'overload',
    'override',
    'Protocol',
    'reveal_type',
    'runtime',
    'runtime_checkable',
    'Text',
    'TypeAlias',
    'TypeGuard',
    'TYPE_CHECKING',
    'Never',
    'NoReturn',
    'Required',
    'NotRequired',
]

# for backward compatibility
PEP_560 = True
GenericMeta = type

# The functions below are modified copies of typing internal helpers.
# They are needed by _ProtocolMeta and they provide support for PEP 646.

_marker = object()


def _check_generic(cls, parameters, elen=_marker):
    """Check correct count for parameters of a generic cls (internal helper).
    This gives a nice error message in case of count mismatch.
    """
    if not elen:
        raise TypeError(f"{cls} is not a generic class")
    if elen is _marker:
        if not hasattr(cls, "__parameters__") or not cls.__parameters__:
            raise TypeError(f"{cls} is not a generic class")
        elen = len(cls.__parameters__)
    alen = len(parameters)
    if alen != elen:
        if hasattr(cls, "__parameters__"):
            parameters = [p for p in cls.__parameters__ if not _is_unpack(p)]
            num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters)
            if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples):
                return
        raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};"
                        f" actual {alen}, expected {elen}")


if sys.version_info >= (3, 10):
    def _should_collect_from_parameters(t):
        return isinstance(
            t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType)
        )
elif sys.version_info >= (3, 9):
    def _should_collect_from_parameters(t):
        return isinstance(t, (typing._GenericAlias, _types.GenericAlias))
else:
    def _should_collect_from_parameters(t):
        return isinstance(t, typing._GenericAlias) and not t._special


def _collect_type_vars(types, typevar_types=None):
    """Collect all type variable contained in types in order of
    first appearance (lexicographic order). For example::

        _collect_type_vars((T, List[S, T])) == (T, S)
    """
    if typevar_types is None:
        typevar_types = typing.TypeVar
    tvars = []
    for t in types:
        if (
            isinstance(t, typevar_types) and
            t not in tvars and
            not _is_unpack(t)
        ):
            tvars.append(t)
        if _should_collect_from_parameters(t):
            tvars.extend([t for t in t.__parameters__ if t not in tvars])
    return tuple(tvars)


NoReturn = typing.NoReturn

# Some unconstrained type variables.  These are used by the container types.
# (These are not for export.)
T = typing.TypeVar('T')  # Any type.
KT = typing.TypeVar('KT')  # Key type.
VT = typing.TypeVar('VT')  # Value type.
T_co = typing.TypeVar('T_co', covariant=True)  # Any type covariant containers.
T_contra = typing.TypeVar('T_contra', contravariant=True)  # Ditto contravariant.


if sys.version_info >= (3, 11):
    from typing import Any
else:

    class _AnyMeta(type):
        def __instancecheck__(self, obj):
            if self is Any:
                raise TypeError("typing_extensions.Any cannot be used with isinstance()")
            return super().__instancecheck__(obj)

        def __repr__(self):
            if self is Any:
                return "typing_extensions.Any"
            return super().__repr__()

    class Any(metaclass=_AnyMeta):
        """Special type indicating an unconstrained type.
        - Any is compatible with every type.
        - Any assumed to have all methods.
        - All values assumed to be instances of Any.
        Note that all the above statements are true from the point of view of
        static type checkers. At runtime, Any should not be used with instance
        checks.
        """
        def __new__(cls, *args, **kwargs):
            if cls is Any:
                raise TypeError("Any cannot be instantiated")
            return super().__new__(cls, *args, **kwargs)


ClassVar = typing.ClassVar

# On older versions of typing there is an internal class named "Final".
# 3.8+
if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7):
    Final = typing.Final
# 3.7
else:
    class _FinalForm(typing._SpecialForm, _root=True):

        def __repr__(self):
            return 'typing_extensions.' + self._name

        def __getitem__(self, parameters):
            item = typing._type_check(parameters,
                                      f'{self._name} accepts only a single type.')
            return typing._GenericAlias(self, (item,))

    Final = _FinalForm('Final',
                       doc="""A special typing construct to indicate that a name
                       cannot be re-assigned or overridden in a subclass.
                       For example:

                           MAX_SIZE: Final = 9000
                           MAX_SIZE += 1  # Error reported by type checker

                           class Connection:
                               TIMEOUT: Final[int] = 10
                           class FastConnector(Connection):
                               TIMEOUT = 1  # Error reported by type checker

                       There is no runtime checking of these properties.""")

if sys.version_info >= (3, 11):
    final = typing.final
else:
    # @final exists in 3.8+, but we backport it for all versions
    # before 3.11 to keep support for the __final__ attribute.
    # See https://bugs.python.org/issue46342
    def final(f):
        """This decorator can be used to indicate to type checkers that
        the decorated method cannot be overridden, and decorated class
        cannot be subclassed. For example:

            class Base:
                @final
                def done(self) -> None:
                    ...
            class Sub(Base):
                def done(self) -> None:  # Error reported by type checker
                    ...
            @final
            class Leaf:
                ...
            class Other(Leaf):  # Error reported by type checker
                ...

        There is no runtime checking of these properties. The decorator
        sets the ``__final__`` attribute to ``True`` on the decorated object
        to allow runtime introspection.
        """
        try:
            f.__final__ = True
        except (AttributeError, TypeError):
            # Skip the attribute silently if it is not writable.
            # AttributeError happens if the object has __slots__ or a
            # read-only property, TypeError if it's a builtin class.
            pass
        return f


def IntVar(name):
    return typing.TypeVar(name)


# 3.8+:
if hasattr(typing, 'Literal'):
    Literal = typing.Literal
# 3.7:
else:
    class _LiteralForm(typing._SpecialForm, _root=True):

        def __repr__(self):
            return 'typing_extensions.' + self._name

        def __getitem__(self, parameters):
            return typing._GenericAlias(self, parameters)

    Literal = _LiteralForm('Literal',
                           doc="""A type that can be used to indicate to type checkers
                           that the corresponding value has a value literally equivalent
                           to the provided parameter. For example:

                               var: Literal[4] = 4

                           The type checker understands that 'var' is literally equal to
                           the value 4 and no other value.

                           Literal[...] cannot be subclassed. There is no runtime
                           checking verifying that the parameter is actually a value
                           instead of a type.""")


_overload_dummy = typing._overload_dummy  # noqa


if hasattr(typing, "get_overloads"):  # 3.11+
    overload = typing.overload
    get_overloads = typing.get_overloads
    clear_overloads = typing.clear_overloads
else:
    # {module: {qualname: {firstlineno: func}}}
    _overload_registry = collections.defaultdict(
        functools.partial(collections.defaultdict, dict)
    )

    def overload(func):
        """Decorator for overloaded functions/methods.

        In a stub file, place two or more stub definitions for the same
        function in a row, each decorated with @overload.  For example:

        @overload
        def utf8(value: None) -> None: ...
        @overload
        def utf8(value: bytes) -> bytes: ...
        @overload
        def utf8(value: str) -> bytes: ...

        In a non-stub file (i.e. a regular .py file), do the same but
        follow it with an implementation.  The implementation should *not*
        be decorated with @overload.  For example:

        @overload
        def utf8(value: None) -> None: ...
        @overload
        def utf8(value: bytes) -> bytes: ...
        @overload
        def utf8(value: str) -> bytes: ...
        def utf8(value):
            # implementation goes here

        The overloads for a function can be retrieved at runtime using the
        get_overloads() function.
        """
        # classmethod and staticmethod
        f = getattr(func, "__func__", func)
        try:
            _overload_registry[f.__module__][f.__qualname__][
                f.__code__.co_firstlineno
            ] = func
        except AttributeError:
            # Not a normal function; ignore.
            pass
        return _overload_dummy

    def get_overloads(func):
        """Return all defined overloads for *func* as a sequence."""
        # classmethod and staticmethod
        f = getattr(func, "__func__", func)
        if f.__module__ not in _overload_registry:
            return []
        mod_dict = _overload_registry[f.__module__]
        if f.__qualname__ not in mod_dict:
            return []
        return list(mod_dict[f.__qualname__].values())

    def clear_overloads():
        """Clear all overloads in the registry."""
        _overload_registry.clear()


# This is not a real generic class.  Don't use outside annotations.
Type = typing.Type

# Various ABCs mimicking those in collections.abc.
# A few are simply re-exported for completeness.


Awaitable = typing.Awaitable
Coroutine = typing.Coroutine
AsyncIterable = typing.AsyncIterable
AsyncIterator = typing.AsyncIterator
Deque = typing.Deque
ContextManager = typing.ContextManager
AsyncContextManager = typing.AsyncContextManager
DefaultDict = typing.DefaultDict

# 3.7.2+
if hasattr(typing, 'OrderedDict'):
    OrderedDict = typing.OrderedDict
# 3.7.0-3.7.2
else:
    OrderedDict = typing._alias(collections.OrderedDict, (KT, VT))

Counter = typing.Counter
ChainMap = typing.ChainMap
AsyncGenerator = typing.AsyncGenerator
NewType = typing.NewType
Text = typing.Text
TYPE_CHECKING = typing.TYPE_CHECKING


_PROTO_WHITELIST = ['Callable', 'Awaitable',
                    'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator',
                    'Hashable', 'Sized', 'Container', 'Collection', 'Reversible',
                    'ContextManager', 'AsyncContextManager']


def _get_protocol_attrs(cls):
    attrs = set()
    for base in cls.__mro__[:-1]:  # without object
        if base.__name__ in ('Protocol', 'Generic'):
            continue
        annotations = getattr(base, '__annotations__', {})
        for attr in list(base.__dict__.keys()) + list(annotations.keys()):
            if (not attr.startswith('_abc_') and attr not in (
                    '__abstractmethods__', '__annotations__', '__weakref__',
                    '_is_protocol', '_is_runtime_protocol', '__dict__',
                    '__args__', '__slots__',
                    '__next_in_mro__', '__parameters__', '__origin__',
                    '__orig_bases__', '__extra__', '__tree_hash__',
                    '__doc__', '__subclasshook__', '__init__', '__new__',
                    '__module__', '_MutableMapping__marker', '_gorg')):
                attrs.add(attr)
    return attrs


def _is_callable_members_only(cls):
    return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls))


def _maybe_adjust_parameters(cls):
    """Helper function used in Protocol.__init_subclass__ and _TypedDictMeta.__new__.

    The contents of this function are very similar
    to logic found in typing.Generic.__init_subclass__
    on the CPython main branch.
    """
    tvars = []
    if '__orig_bases__' in cls.__dict__:
        tvars = typing._collect_type_vars(cls.__orig_bases__)
        # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn].
        # If found, tvars must be a subset of it.
        # If not found, tvars is it.
        # Also check for and reject plain Generic,
        # and reject multiple Generic[...] and/or Protocol[...].
        gvars = None
        for base in cls.__orig_bases__:
            if (isinstance(base, typing._GenericAlias) and
                    base.__origin__ in (typing.Generic, Protocol)):
                # for error messages
                the_base = base.__origin__.__name__
                if gvars is not None:
                    raise TypeError(
                        "Cannot inherit from Generic[...]"
                        " and/or Protocol[...] multiple types.")
                gvars = base.__parameters__
        if gvars is None:
            gvars = tvars
        else:
            tvarset = set(tvars)
            gvarset = set(gvars)
            if not tvarset <= gvarset:
                s_vars = ', '.join(str(t) for t in tvars if t not in gvarset)
                s_args = ', '.join(str(g) for g in gvars)
                raise TypeError(f"Some type variables ({s_vars}) are"
                                f" not listed in {the_base}[{s_args}]")
            tvars = gvars
    cls.__parameters__ = tuple(tvars)


# 3.8+
if hasattr(typing, 'Protocol'):
    Protocol = typing.Protocol
# 3.7
else:

    def _no_init(self, *args, **kwargs):
        if type(self)._is_protocol:
            raise TypeError('Protocols cannot be instantiated')

    class _ProtocolMeta(abc.ABCMeta):  # noqa: B024
        # This metaclass is a bit unfortunate and exists only because of the lack
        # of __instancehook__.
        def __instancecheck__(cls, instance):
            # We need this method for situations where attributes are
            # assigned in __init__.
            if ((not getattr(cls, '_is_protocol', False) or
                 _is_callable_members_only(cls)) and
                    issubclass(instance.__class__, cls)):
                return True
            if cls._is_protocol:
                if all(hasattr(instance, attr) and
                       (not callable(getattr(cls, attr, None)) or
                        getattr(instance, attr) is not None)
                       for attr in _get_protocol_attrs(cls)):
                    return True
            return super().__instancecheck__(instance)

    class Protocol(metaclass=_ProtocolMeta):
        # There is quite a lot of overlapping code with typing.Generic.
        # Unfortunately it is hard to avoid this while these live in two different
        # modules. The duplicated code will be removed when Protocol is moved to typing.
        """Base class for protocol classes. Protocol classes are defined as::

            class Proto(Protocol):
                def meth(self) -> int:
                    ...

        Such classes are primarily used with static type checkers that recognize
        structural subtyping (static duck-typing), for example::

            class C:
                def meth(self) -> int:
                    return 0

            def func(x: Proto) -> int:
                return x.meth()

            func(C())  # Passes static type check

        See PEP 544 for details. Protocol classes decorated with
        @typing_extensions.runtime act as simple-minded runtime protocol that checks
        only the presence of given attributes, ignoring their type signatures.

        Protocol classes can be generic, they are defined as::

            class GenProto(Protocol[T]):
                def meth(self) -> T:
                    ...
        """
        __slots__ = ()
        _is_protocol = True

        def __new__(cls, *args, **kwds):
            if cls is Protocol:
                raise TypeError("Type Protocol cannot be instantiated; "
                                "it can only be used as a base class")
            return super().__new__(cls)

        @typing._tp_cache
        def __class_getitem__(cls, params):
            if not isinstance(params, tuple):
                params = (params,)
            if not params and cls is not typing.Tuple:
                raise TypeError(
                    f"Parameter list to {cls.__qualname__}[...] cannot be empty")
            msg = "Parameters to generic types must be types."
            params = tuple(typing._type_check(p, msg) for p in params)  # noqa
            if cls is Protocol:
                # Generic can only be subscripted with unique type variables.
                if not all(isinstance(p, typing.TypeVar) for p in params):
                    i = 0
                    while isinstance(params[i], typing.TypeVar):
                        i += 1
                    raise TypeError(
                        "Parameters to Protocol[...] must all be type variables."
                        f" Parameter {i + 1} is {params[i]}")
                if len(set(params)) != len(params):
                    raise TypeError(
                        "Parameters to Protocol[...] must all be unique")
            else:
                # Subscripting a regular Generic subclass.
                _check_generic(cls, params, len(cls.__parameters__))
            return typing._GenericAlias(cls, params)

        def __init_subclass__(cls, *args, **kwargs):
            if '__orig_bases__' in cls.__dict__:
                error = typing.Generic in cls.__orig_bases__
            else:
                error = typing.Generic in cls.__bases__
            if error:
                raise TypeError("Cannot inherit from plain Generic")
            _maybe_adjust_parameters(cls)

            # Determine if this is a protocol or a concrete subclass.
            if not cls.__dict__.get('_is_protocol', None):
                cls._is_protocol = any(b is Protocol for b in cls.__bases__)

            # Set (or override) the protocol subclass hook.
            def _proto_hook(other):
                if not cls.__dict__.get('_is_protocol', None):
                    return NotImplemented
                if not getattr(cls, '_is_runtime_protocol', False):
                    if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']:
                        return NotImplemented
                    raise TypeError("Instance and class checks can only be used with"
                                    " @runtime protocols")
                if not _is_callable_members_only(cls):
                    if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']:
                        return NotImplemented
                    raise TypeError("Protocols with non-method members"
                                    " don't support issubclass()")
                if not isinstance(other, type):
                    # Same error as for issubclass(1, int)
                    raise TypeError('issubclass() arg 1 must be a class')
                for attr in _get_protocol_attrs(cls):
                    for base in other.__mro__:
                        if attr in base.__dict__:
                            if base.__dict__[attr] is None:
                                return NotImplemented
                            break
                        annotations = getattr(base, '__annotations__', {})
                        if (isinstance(annotations, typing.Mapping) and
                                attr in annotations and
                                isinstance(other, _ProtocolMeta) and
                                other._is_protocol):
                            break
                    else:
                        return NotImplemented
                return True
            if '__subclasshook__' not in cls.__dict__:
                cls.__subclasshook__ = _proto_hook

            # We have nothing more to do for non-protocols.
            if not cls._is_protocol:
                return

            # Check consistency of bases.
            for base in cls.__bases__:
                if not (base in (object, typing.Generic) or
                        base.__module__ == 'collections.abc' and
                        base.__name__ in _PROTO_WHITELIST or
                        isinstance(base, _ProtocolMeta) and base._is_protocol):
                    raise TypeError('Protocols can only inherit from other'
                                    f' protocols, got {repr(base)}')
            cls.__init__ = _no_init


# 3.8+
if hasattr(typing, 'runtime_checkable'):
    runtime_checkable = typing.runtime_checkable
# 3.7
else:
    def runtime_checkable(cls):
        """Mark a protocol class as a runtime protocol, so that it
        can be used with isinstance() and issubclass(). Raise TypeError
        if applied to a non-protocol class.

        This allows a simple-minded structural check very similar to the
        one-offs in collections.abc such as Hashable.
        """
        if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol:
            raise TypeError('@runtime_checkable can be only applied to protocol classes,'
                            f' got {cls!r}')
        cls._is_runtime_protocol = True
        return cls


# Exists for backwards compatibility.
runtime = runtime_checkable


# 3.8+
if hasattr(typing, 'SupportsIndex'):
    SupportsIndex = typing.SupportsIndex
# 3.7
else:
    @runtime_checkable
    class SupportsIndex(Protocol):
        __slots__ = ()

        @abc.abstractmethod
        def __index__(self) -> int:
            pass


if hasattr(typing, "Required"):
    # The standard library TypedDict in Python 3.8 does not store runtime information
    # about which (if any) keys are optional.  See https://bugs.python.org/issue38834
    # The standard library TypedDict in Python 3.9.0/1 does not honour the "total"
    # keyword with old-style TypedDict().  See https://bugs.python.org/issue42059
    # The standard library TypedDict below Python 3.11 does not store runtime
    # information about optional and required keys when using Required or NotRequired.
    # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11.
    TypedDict = typing.TypedDict
    _TypedDictMeta = typing._TypedDictMeta
    is_typeddict = typing.is_typeddict
else:
    def _check_fails(cls, other):
        try:
            if sys._getframe(1).f_globals['__name__'] not in ['abc',
                                                              'functools',
                                                              'typing']:
                # Typed dicts are only for static structural subtyping.
                raise TypeError('TypedDict does not support instance and class checks')
        except (AttributeError, ValueError):
            pass
        return False

    def _dict_new(*args, **kwargs):
        if not args:
            raise TypeError('TypedDict.__new__(): not enough arguments')
        _, args = args[0], args[1:]  # allow the "cls" keyword be passed
        return dict(*args, **kwargs)

    _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)'

    def _typeddict_new(*args, total=True, **kwargs):
        if not args:
            raise TypeError('TypedDict.__new__(): not enough arguments')
        _, args = args[0], args[1:]  # allow the "cls" keyword be passed
        if args:
            typename, args = args[0], args[1:]  # allow the "_typename" keyword be passed
        elif '_typename' in kwargs:
            typename = kwargs.pop('_typename')
            import warnings
            warnings.warn("Passing '_typename' as keyword argument is deprecated",
                          DeprecationWarning, stacklevel=2)
        else:
            raise TypeError("TypedDict.__new__() missing 1 required positional "
                            "argument: '_typename'")
        if args:
            try:
                fields, = args  # allow the "_fields" keyword be passed
            except ValueError:
                raise TypeError('TypedDict.__new__() takes from 2 to 3 '
                                f'positional arguments but {len(args) + 2} '
                                'were given')
        elif '_fields' in kwargs and len(kwargs) == 1:
            fields = kwargs.pop('_fields')
            import warnings
            warnings.warn("Passing '_fields' as keyword argument is deprecated",
                          DeprecationWarning, stacklevel=2)
        else:
            fields = None

        if fields is None:
            fields = kwargs
        elif kwargs:
            raise TypeError("TypedDict takes either a dict or keyword arguments,"
                            " but not both")

        ns = {'__annotations__': dict(fields)}
        try:
            # Setting correct module is necessary to make typed dict classes pickleable.
            ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__')
        except (AttributeError, ValueError):
            pass

        return _TypedDictMeta(typename, (), ns, total=total)

    _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,'
                                         ' /, *, total=True, **kwargs)')

    class _TypedDictMeta(type):
        def __init__(cls, name, bases, ns, total=True):
            super().__init__(name, bases, ns)

        def __new__(cls, name, bases, ns, total=True):
            # Create new typed dict class object.
            # This method is called directly when TypedDict is subclassed,
            # or via _typeddict_new when TypedDict is instantiated. This way
            # TypedDict supports all three syntaxes described in its docstring.
            # Subclasses and instances of TypedDict return actual dictionaries
            # via _dict_new.
            ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new
            # Don't insert typing.Generic into __bases__ here,
            # or Generic.__init_subclass__ will raise TypeError
            # in the super().__new__() call.
            # Instead, monkey-patch __bases__ onto the class after it's been created.
            tp_dict = super().__new__(cls, name, (dict,), ns)

            if any(issubclass(base, typing.Generic) for base in bases):
                tp_dict.__bases__ = (typing.Generic, dict)
                _maybe_adjust_parameters(tp_dict)

            annotations = {}
            own_annotations = ns.get('__annotations__', {})
            msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
            own_annotations = {
                n: typing._type_check(tp, msg) for n, tp in own_annotations.items()
            }
            required_keys = set()
            optional_keys = set()

            for base in bases:
                annotations.update(base.__dict__.get('__annotations__', {}))
                required_keys.update(base.__dict__.get('__required_keys__', ()))
                optional_keys.update(base.__dict__.get('__optional_keys__', ()))

            annotations.update(own_annotations)
            for annotation_key, annotation_type in own_annotations.items():
                annotation_origin = get_origin(annotation_type)
                if annotation_origin is Annotated:
                    annotation_args = get_args(annotation_type)
                    if annotation_args:
                        annotation_type = annotation_args[0]
                        annotation_origin = get_origin(annotation_type)

                if annotation_origin is Required:
                    required_keys.add(annotation_key)
                elif annotation_origin is NotRequired:
                    optional_keys.add(annotation_key)
                elif total:
                    required_keys.add(annotation_key)
                else:
                    optional_keys.add(annotation_key)

            tp_dict.__annotations__ = annotations
            tp_dict.__required_keys__ = frozenset(required_keys)
            tp_dict.__optional_keys__ = frozenset(optional_keys)
            if not hasattr(tp_dict, '__total__'):
                tp_dict.__total__ = total
            return tp_dict

        __instancecheck__ = __subclasscheck__ = _check_fails

    TypedDict = _TypedDictMeta('TypedDict', (dict,), {})
    TypedDict.__module__ = __name__
    TypedDict.__doc__ = \
        """A simple typed name space. At runtime it is equivalent to a plain dict.

        TypedDict creates a dictionary type that expects all of its
        instances to have a certain set of keys, with each key
        associated with a value of a consistent type. This expectation
        is not checked at runtime but is only enforced by type checkers.
        Usage::

            class Point2D(TypedDict):
                x: int
                y: int
                label: str

            a: Point2D = {'x': 1, 'y': 2, 'label': 'good'}  # OK
            b: Point2D = {'z': 3, 'label': 'bad'}           # Fails type check

            assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')

        The type info can be accessed via the Point2D.__annotations__ dict, and
        the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets.
        TypedDict supports two additional equivalent forms::

            Point2D = TypedDict('Point2D', x=int, y=int, label=str)
            Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})

        The class syntax is only supported in Python 3.6+, while two other
        syntax forms work for Python 2.7 and 3.2+
        """

    if hasattr(typing, "_TypedDictMeta"):
        _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta)
    else:
        _TYPEDDICT_TYPES = (_TypedDictMeta,)

    def is_typeddict(tp):
        """Check if an annotation is a TypedDict class

        For example::
            class Film(TypedDict):
                title: str
                year: int

            is_typeddict(Film)  # => True
            is_typeddict(Union[list, str])  # => False
        """
        return isinstance(tp, tuple(_TYPEDDICT_TYPES))


if hasattr(typing, "assert_type"):
    assert_type = typing.assert_type

else:
    def assert_type(__val, __typ):
        """Assert (to the type checker) that the value is of the given type.

        When the type checker encounters a call to assert_type(), it
        emits an error if the value is not of the specified type::

            def greet(name: str) -> None:
                assert_type(name, str)  # ok
                assert_type(name, int)  # type checker error

        At runtime this returns the first argument unchanged and otherwise
        does nothing.
        """
        return __val


if hasattr(typing, "Required"):
    get_type_hints = typing.get_type_hints
else:
    import functools
    import types

    # replaces _strip_annotations()
    def _strip_extras(t):
        """Strips Annotated, Required and NotRequired from a given type."""
        if isinstance(t, _AnnotatedAlias):
            return _strip_extras(t.__origin__)
        if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired):
            return _strip_extras(t.__args__[0])
        if isinstance(t, typing._GenericAlias):
            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
            if stripped_args == t.__args__:
                return t
            return t.copy_with(stripped_args)
        if hasattr(types, "GenericAlias") and isinstance(t, types.GenericAlias):
            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
            if stripped_args == t.__args__:
                return t
            return types.GenericAlias(t.__origin__, stripped_args)
        if hasattr(types, "UnionType") and isinstance(t, types.UnionType):
            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
            if stripped_args == t.__args__:
                return t
            return functools.reduce(operator.or_, stripped_args)

        return t

    def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
        """Return type hints for an object.

        This is often the same as obj.__annotations__, but it handles
        forward references encoded as string literals, adds Optional[t] if a
        default value equal to None is set and recursively replaces all
        'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T'
        (unless 'include_extras=True').

        The argument may be a module, class, method, or function. The annotations
        are returned as a dictionary. For classes, annotations include also
        inherited members.

        TypeError is raised if the argument is not of a type that can contain
        annotations, and an empty dictionary is returned if no annotations are
        present.

        BEWARE -- the behavior of globalns and localns is counterintuitive
        (unless you are familiar with how eval() and exec() work).  The
        search order is locals first, then globals.

        - If no dict arguments are passed, an attempt is made to use the
          globals from obj (or the respective module's globals for classes),
          and these are also used as the locals.  If the object does not appear
          to have globals, an empty dictionary is used.

        - If one dict argument is passed, it is used for both globals and
          locals.

        - If two dict arguments are passed, they specify globals and
          locals, respectively.
        """
        if hasattr(typing, "Annotated"):
            hint = typing.get_type_hints(
                obj, globalns=globalns, localns=localns, include_extras=True
            )
        else:
            hint = typing.get_type_hints(obj, globalns=globalns, localns=localns)
        if include_extras:
            return hint
        return {k: _strip_extras(t) for k, t in hint.items()}


# Python 3.9+ has PEP 593 (Annotated)
if hasattr(typing, 'Annotated'):
    Annotated = typing.Annotated
    # Not exported and not a public API, but needed for get_origin() and get_args()
    # to work.
    _AnnotatedAlias = typing._AnnotatedAlias
# 3.7-3.8
else:
    class _AnnotatedAlias(typing._GenericAlias, _root=True):
        """Runtime representation of an annotated type.

        At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't'
        with extra annotations. The alias behaves like a normal typing alias,
        instantiating is the same as instantiating the underlying type, binding
        it to types is also the same.
        """
        def __init__(self, origin, metadata):
            if isinstance(origin, _AnnotatedAlias):
                metadata = origin.__metadata__ + metadata
                origin = origin.__origin__
            super().__init__(origin, origin)
            self.__metadata__ = metadata

        def copy_with(self, params):
            assert len(params) == 1
            new_type = params[0]
            return _AnnotatedAlias(new_type, self.__metadata__)

        def __repr__(self):
            return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, "
                    f"{', '.join(repr(a) for a in self.__metadata__)}]")

        def __reduce__(self):
            return operator.getitem, (
                Annotated, (self.__origin__,) + self.__metadata__
            )

        def __eq__(self, other):
            if not isinstance(other, _AnnotatedAlias):
                return NotImplemented
            if self.__origin__ != other.__origin__:
                return False
            return self.__metadata__ == other.__metadata__

        def __hash__(self):
            return hash((self.__origin__, self.__metadata__))

    class Annotated:
        """Add context specific metadata to a type.

        Example: Annotated[int, runtime_check.Unsigned] indicates to the
        hypothetical runtime_check module that this type is an unsigned int.
        Every other consumer of this type can ignore this metadata and treat
        this type as int.

        The first argument to Annotated must be a valid type (and will be in
        the __origin__ field), the remaining arguments are kept as a tuple in
        the __extra__ field.

        Details:

        - It's an error to call `Annotated` with less than two arguments.
        - Nested Annotated are flattened::

            Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3]

        - Instantiating an annotated type is equivalent to instantiating the
        underlying type::

            Annotated[C, Ann1](5) == C(5)

        - Annotated can be used as a generic type alias::

            Optimized = Annotated[T, runtime.Optimize()]
            Optimized[int] == Annotated[int, runtime.Optimize()]

            OptimizedList = Annotated[List[T], runtime.Optimize()]
            OptimizedList[int] == Annotated[List[int], runtime.Optimize()]
        """

        __slots__ = ()

        def __new__(cls, *args, **kwargs):
            raise TypeError("Type Annotated cannot be instantiated.")

        @typing._tp_cache
        def __class_getitem__(cls, params):
            if not isinstance(params, tuple) or len(params) < 2:
                raise TypeError("Annotated[...] should be used "
                                "with at least two arguments (a type and an "
                                "annotation).")
            allowed_special_forms = (ClassVar, Final)
            if get_origin(params[0]) in allowed_special_forms:
                origin = params[0]
            else:
                msg = "Annotated[t, ...]: t must be a type."
                origin = typing._type_check(params[0], msg)
            metadata = tuple(params[1:])
            return _AnnotatedAlias(origin, metadata)

        def __init_subclass__(cls, *args, **kwargs):
            raise TypeError(
                f"Cannot subclass {cls.__module__}.Annotated"
            )

# Python 3.8 has get_origin() and get_args() but those implementations aren't
# Annotated-aware, so we can't use those. Python 3.9's versions don't support
# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do.
if sys.version_info[:2] >= (3, 10):
    get_origin = typing.get_origin
    get_args = typing.get_args
# 3.7-3.9
else:
    try:
        # 3.9+
        from typing import _BaseGenericAlias
    except ImportError:
        _BaseGenericAlias = typing._GenericAlias
    try:
        # 3.9+
        from typing import GenericAlias as _typing_GenericAlias
    except ImportError:
        _typing_GenericAlias = typing._GenericAlias

    def get_origin(tp):
        """Get the unsubscripted version of a type.

        This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar
        and Annotated. Return None for unsupported types. Examples::

            get_origin(Literal[42]) is Literal
            get_origin(int) is None
            get_origin(ClassVar[int]) is ClassVar
            get_origin(Generic) is Generic
            get_origin(Generic[T]) is Generic
            get_origin(Union[T, int]) is Union
            get_origin(List[Tuple[T, T]][int]) == list
            get_origin(P.args) is P
        """
        if isinstance(tp, _AnnotatedAlias):
            return Annotated
        if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias,
                           ParamSpecArgs, ParamSpecKwargs)):
            return tp.__origin__
        if tp is typing.Generic:
            return typing.Generic
        return None

    def get_args(tp):
        """Get type arguments with all substitutions performed.

        For unions, basic simplifications used by Union constructor are performed.
        Examples::
            get_args(Dict[str, int]) == (str, int)
            get_args(int) == ()
            get_args(Union[int, Union[T, int], str][int]) == (int, str)
            get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
            get_args(Callable[[], T][int]) == ([], int)
        """
        if isinstance(tp, _AnnotatedAlias):
            return (tp.__origin__,) + tp.__metadata__
        if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)):
            if getattr(tp, "_special", False):
                return ()
            res = tp.__args__
            if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis:
                res = (list(res[:-1]), res[-1])
            return res
        return ()


# 3.10+
if hasattr(typing, 'TypeAlias'):
    TypeAlias = typing.TypeAlias
# 3.9
elif sys.version_info[:2] >= (3, 9):
    class _TypeAliasForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

    @_TypeAliasForm
    def TypeAlias(self, parameters):
        """Special marker indicating that an assignment should
        be recognized as a proper type alias definition by type
        checkers.

        For example::

            Predicate: TypeAlias = Callable[..., bool]

        It's invalid when used anywhere except as in the example above.
        """
        raise TypeError(f"{self} is not subscriptable")
# 3.7-3.8
else:
    class _TypeAliasForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

    TypeAlias = _TypeAliasForm('TypeAlias',
                               doc="""Special marker indicating that an assignment should
                               be recognized as a proper type alias definition by type
                               checkers.

                               For example::

                                   Predicate: TypeAlias = Callable[..., bool]

                               It's invalid when used anywhere except as in the example
                               above.""")


class _DefaultMixin:
    """Mixin for TypeVarLike defaults."""

    __slots__ = ()

    def __init__(self, default):
        if isinstance(default, (tuple, list)):
            self.__default__ = tuple((typing._type_check(d, "Default must be a type")
                                      for d in default))
        elif default:
            self.__default__ = typing._type_check(default, "Default must be a type")
        else:
            self.__default__ = None


# Add default and infer_variance parameters from PEP 696 and 695
class TypeVar(typing.TypeVar, _DefaultMixin, _root=True):
    """Type variable."""

    __module__ = 'typing'

    def __init__(self, name, *constraints, bound=None,
                 covariant=False, contravariant=False,
                 default=None, infer_variance=False):
        super().__init__(name, *constraints, bound=bound, covariant=covariant,
                         contravariant=contravariant)
        _DefaultMixin.__init__(self, default)
        self.__infer_variance__ = infer_variance

        # for pickling:
        try:
            def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
        except (AttributeError, ValueError):
            def_mod = None
        if def_mod != 'typing_extensions':
            self.__module__ = def_mod


# Python 3.10+ has PEP 612
if hasattr(typing, 'ParamSpecArgs'):
    ParamSpecArgs = typing.ParamSpecArgs
    ParamSpecKwargs = typing.ParamSpecKwargs
# 3.7-3.9
else:
    class _Immutable:
        """Mixin to indicate that object should not be copied."""
        __slots__ = ()

        def __copy__(self):
            return self

        def __deepcopy__(self, memo):
            return self

    class ParamSpecArgs(_Immutable):
        """The args for a ParamSpec object.

        Given a ParamSpec object P, P.args is an instance of ParamSpecArgs.

        ParamSpecArgs objects have a reference back to their ParamSpec:

        P.args.__origin__ is P

        This type is meant for runtime introspection and has no special meaning to
        static type checkers.
        """
        def __init__(self, origin):
            self.__origin__ = origin

        def __repr__(self):
            return f"{self.__origin__.__name__}.args"

        def __eq__(self, other):
            if not isinstance(other, ParamSpecArgs):
                return NotImplemented
            return self.__origin__ == other.__origin__

    class ParamSpecKwargs(_Immutable):
        """The kwargs for a ParamSpec object.

        Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs.

        ParamSpecKwargs objects have a reference back to their ParamSpec:

        P.kwargs.__origin__ is P

        This type is meant for runtime introspection and has no special meaning to
        static type checkers.
        """
        def __init__(self, origin):
            self.__origin__ = origin

        def __repr__(self):
            return f"{self.__origin__.__name__}.kwargs"

        def __eq__(self, other):
            if not isinstance(other, ParamSpecKwargs):
                return NotImplemented
            return self.__origin__ == other.__origin__

# 3.10+
if hasattr(typing, 'ParamSpec'):

    # Add default Parameter - PEP 696
    class ParamSpec(typing.ParamSpec, _DefaultMixin, _root=True):
        """Parameter specification variable."""

        __module__ = 'typing'

        def __init__(self, name, *, bound=None, covariant=False, contravariant=False,
                     default=None):
            super().__init__(name, bound=bound, covariant=covariant,
                             contravariant=contravariant)
            _DefaultMixin.__init__(self, default)

            # for pickling:
            try:
                def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
            except (AttributeError, ValueError):
                def_mod = None
            if def_mod != 'typing_extensions':
                self.__module__ = def_mod

# 3.7-3.9
else:

    # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
    class ParamSpec(list, _DefaultMixin):
        """Parameter specification variable.

        Usage::

           P = ParamSpec('P')

        Parameter specification variables exist primarily for the benefit of static
        type checkers.  They are used to forward the parameter types of one
        callable to another callable, a pattern commonly found in higher order
        functions and decorators.  They are only valid when used in ``Concatenate``,
        or s the first argument to ``Callable``. In Python 3.10 and higher,
        they are also supported in user-defined Generics at runtime.
        See class Generic for more information on generic types.  An
        example for annotating a decorator::

           T = TypeVar('T')
           P = ParamSpec('P')

           def add_logging(f: Callable[P, T]) -> Callable[P, T]:
               '''A type-safe decorator to add logging to a function.'''
               def inner(*args: P.args, **kwargs: P.kwargs) -> T:
                   logging.info(f'{f.__name__} was called')
                   return f(*args, **kwargs)
               return inner

           @add_logging
           def add_two(x: float, y: float) -> float:
               '''Add two numbers together.'''
               return x + y

        Parameter specification variables defined with covariant=True or
        contravariant=True can be used to declare covariant or contravariant
        generic types.  These keyword arguments are valid, but their actual semantics
        are yet to be decided.  See PEP 612 for details.

        Parameter specification variables can be introspected. e.g.:

           P.__name__ == 'T'
           P.__bound__ == None
           P.__covariant__ == False
           P.__contravariant__ == False

        Note that only parameter specification variables defined in global scope can
        be pickled.
        """

        # Trick Generic __parameters__.
        __class__ = typing.TypeVar

        @property
        def args(self):
            return ParamSpecArgs(self)

        @property
        def kwargs(self):
            return ParamSpecKwargs(self)

        def __init__(self, name, *, bound=None, covariant=False, contravariant=False,
                     default=None):
            super().__init__([self])
            self.__name__ = name
            self.__covariant__ = bool(covariant)
            self.__contravariant__ = bool(contravariant)
            if bound:
                self.__bound__ = typing._type_check(bound, 'Bound must be a type.')
            else:
                self.__bound__ = None
            _DefaultMixin.__init__(self, default)

            # for pickling:
            try:
                def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
            except (AttributeError, ValueError):
                def_mod = None
            if def_mod != 'typing_extensions':
                self.__module__ = def_mod

        def __repr__(self):
            if self.__covariant__:
                prefix = '+'
            elif self.__contravariant__:
                prefix = '-'
            else:
                prefix = '~'
            return prefix + self.__name__

        def __hash__(self):
            return object.__hash__(self)

        def __eq__(self, other):
            return self is other

        def __reduce__(self):
            return self.__name__

        # Hack to get typing._type_check to pass.
        def __call__(self, *args, **kwargs):
            pass


# 3.7-3.9
if not hasattr(typing, 'Concatenate'):
    # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
    class _ConcatenateGenericAlias(list):

        # Trick Generic into looking into this for __parameters__.
        __class__ = typing._GenericAlias

        # Flag in 3.8.
        _special = False

        def __init__(self, origin, args):
            super().__init__(args)
            self.__origin__ = origin
            self.__args__ = args

        def __repr__(self):
            _type_repr = typing._type_repr
            return (f'{_type_repr(self.__origin__)}'
                    f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]')

        def __hash__(self):
            return hash((self.__origin__, self.__args__))

        # Hack to get typing._type_check to pass in Generic.
        def __call__(self, *args, **kwargs):
            pass

        @property
        def __parameters__(self):
            return tuple(
                tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec))
            )


# 3.7-3.9
@typing._tp_cache
def _concatenate_getitem(self, parameters):
    if parameters == ():
        raise TypeError("Cannot take a Concatenate of no types.")
    if not isinstance(parameters, tuple):
        parameters = (parameters,)
    if not isinstance(parameters[-1], ParamSpec):
        raise TypeError("The last parameter to Concatenate should be a "
                        "ParamSpec variable.")
    msg = "Concatenate[arg, ...]: each arg must be a type."
    parameters = tuple(typing._type_check(p, msg) for p in parameters)
    return _ConcatenateGenericAlias(self, parameters)


# 3.10+
if hasattr(typing, 'Concatenate'):
    Concatenate = typing.Concatenate
    _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa
# 3.9
elif sys.version_info[:2] >= (3, 9):
    @_TypeAliasForm
    def Concatenate(self, parameters):
        """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
        higher order function which adds, removes or transforms parameters of a
        callable.

        For example::

           Callable[Concatenate[int, P], int]

        See PEP 612 for detailed information.
        """
        return _concatenate_getitem(self, parameters)
# 3.7-8
else:
    class _ConcatenateForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

        def __getitem__(self, parameters):
            return _concatenate_getitem(self, parameters)

    Concatenate = _ConcatenateForm(
        'Concatenate',
        doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
        higher order function which adds, removes or transforms parameters of a
        callable.

        For example::

           Callable[Concatenate[int, P], int]

        See PEP 612 for detailed information.
        """)

# 3.10+
if hasattr(typing, 'TypeGuard'):
    TypeGuard = typing.TypeGuard
# 3.9
elif sys.version_info[:2] >= (3, 9):
    class _TypeGuardForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

    @_TypeGuardForm
    def TypeGuard(self, parameters):
        """Special typing form used to annotate the return type of a user-defined
        type guard function.  ``TypeGuard`` only accepts a single type argument.
        At runtime, functions marked this way should return a boolean.

        ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static
        type checkers to determine a more precise type of an expression within a
        program's code flow.  Usually type narrowing is done by analyzing
        conditional code flow and applying the narrowing to a block of code.  The
        conditional expression here is sometimes referred to as a "type guard".

        Sometimes it would be convenient to use a user-defined boolean function
        as a type guard.  Such a function should use ``TypeGuard[...]`` as its
        return type to alert static type checkers to this intention.

        Using  ``-> TypeGuard`` tells the static type checker that for a given
        function:

        1. The return value is a boolean.
        2. If the return value is ``True``, the type of its argument
        is the type inside ``TypeGuard``.

        For example::

            def is_str(val: Union[str, float]):
                # "isinstance" type guard
                if isinstance(val, str):
                    # Type of ``val`` is narrowed to ``str``
                    ...
                else:
                    # Else, type of ``val`` is narrowed to ``float``.
                    ...

        Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower
        form of ``TypeA`` (it can even be a wider form) and this may lead to
        type-unsafe results.  The main reason is to allow for things like
        narrowing ``List[object]`` to ``List[str]`` even though the latter is not
        a subtype of the former, since ``List`` is invariant.  The responsibility of
        writing type-safe type guards is left to the user.

        ``TypeGuard`` also works with type variables.  For more information, see
        PEP 647 (User-Defined Type Guards).
        """
        item = typing._type_check(parameters, f'{self} accepts only a single type.')
        return typing._GenericAlias(self, (item,))
# 3.7-3.8
else:
    class _TypeGuardForm(typing._SpecialForm, _root=True):

        def __repr__(self):
            return 'typing_extensions.' + self._name

        def __getitem__(self, parameters):
            item = typing._type_check(parameters,
                                      f'{self._name} accepts only a single type')
            return typing._GenericAlias(self, (item,))

    TypeGuard = _TypeGuardForm(
        'TypeGuard',
        doc="""Special typing form used to annotate the return type of a user-defined
        type guard function.  ``TypeGuard`` only accepts a single type argument.
        At runtime, functions marked this way should return a boolean.

        ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static
        type checkers to determine a more precise type of an expression within a
        program's code flow.  Usually type narrowing is done by analyzing
        conditional code flow and applying the narrowing to a block of code.  The
        conditional expression here is sometimes referred to as a "type guard".

        Sometimes it would be convenient to use a user-defined boolean function
        as a type guard.  Such a function should use ``TypeGuard[...]`` as its
        return type to alert static type checkers to this intention.

        Using  ``-> TypeGuard`` tells the static type checker that for a given
        function:

        1. The return value is a boolean.
        2. If the return value is ``True``, the type of its argument
        is the type inside ``TypeGuard``.

        For example::

            def is_str(val: Union[str, float]):
                # "isinstance" type guard
                if isinstance(val, str):
                    # Type of ``val`` is narrowed to ``str``
                    ...
                else:
                    # Else, type of ``val`` is narrowed to ``float``.
                    ...

        Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower
        form of ``TypeA`` (it can even be a wider form) and this may lead to
        type-unsafe results.  The main reason is to allow for things like
        narrowing ``List[object]`` to ``List[str]`` even though the latter is not
        a subtype of the former, since ``List`` is invariant.  The responsibility of
        writing type-safe type guards is left to the user.

        ``TypeGuard`` also works with type variables.  For more information, see
        PEP 647 (User-Defined Type Guards).
        """)


# Vendored from cpython typing._SpecialFrom
class _SpecialForm(typing._Final, _root=True):
    __slots__ = ('_name', '__doc__', '_getitem')

    def __init__(self, getitem):
        self._getitem = getitem
        self._name = getitem.__name__
        self.__doc__ = getitem.__doc__

    def __getattr__(self, item):
        if item in {'__name__', '__qualname__'}:
            return self._name

        raise AttributeError(item)

    def __mro_entries__(self, bases):
        raise TypeError(f"Cannot subclass {self!r}")

    def __repr__(self):
        return f'typing_extensions.{self._name}'

    def __reduce__(self):
        return self._name

    def __call__(self, *args, **kwds):
        raise TypeError(f"Cannot instantiate {self!r}")

    def __or__(self, other):
        return typing.Union[self, other]

    def __ror__(self, other):
        return typing.Union[other, self]

    def __instancecheck__(self, obj):
        raise TypeError(f"{self} cannot be used with isinstance()")

    def __subclasscheck__(self, cls):
        raise TypeError(f"{self} cannot be used with issubclass()")

    @typing._tp_cache
    def __getitem__(self, parameters):
        return self._getitem(self, parameters)


if hasattr(typing, "LiteralString"):
    LiteralString = typing.LiteralString
else:
    @_SpecialForm
    def LiteralString(self, params):
        """Represents an arbitrary literal string.

        Example::

          from typing_extensions import LiteralString

          def query(sql: LiteralString) -> ...:
              ...

          query("SELECT * FROM table")  # ok
          query(f"SELECT * FROM {input()}")  # not ok

        See PEP 675 for details.

        """
        raise TypeError(f"{self} is not subscriptable")


if hasattr(typing, "Self"):
    Self = typing.Self
else:
    @_SpecialForm
    def Self(self, params):
        """Used to spell the type of "self" in classes.

        Example::

          from typing import Self

          class ReturnsSelf:
              def parse(self, data: bytes) -> Self:
                  ...
                  return self

        """

        raise TypeError(f"{self} is not subscriptable")


if hasattr(typing, "Never"):
    Never = typing.Never
else:
    @_SpecialForm
    def Never(self, params):
        """The bottom type, a type that has no members.

        This can be used to define a function that should never be
        called, or a function that never returns::

            from typing_extensions import Never

            def never_call_me(arg: Never) -> None:
                pass

            def int_or_str(arg: int | str) -> None:
                never_call_me(arg)  # type checker error
                match arg:
                    case int():
                        print("It's an int")
                    case str():
                        print("It's a str")
                    case _:
                        never_call_me(arg)  # ok, arg is of type Never

        """

        raise TypeError(f"{self} is not subscriptable")


if hasattr(typing, 'Required'):
    Required = typing.Required
    NotRequired = typing.NotRequired
elif sys.version_info[:2] >= (3, 9):
    class _ExtensionsSpecialForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

    @_ExtensionsSpecialForm
    def Required(self, parameters):
        """A special typing construct to mark a key of a total=False TypedDict
        as required. For example:

            class Movie(TypedDict, total=False):
                title: Required[str]
                year: int

            m = Movie(
                title='The Matrix',  # typechecker error if key is omitted
                year=1999,
            )

        There is no runtime checking that a required key is actually provided
        when instantiating a related TypedDict.
        """
        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
        return typing._GenericAlias(self, (item,))

    @_ExtensionsSpecialForm
    def NotRequired(self, parameters):
        """A special typing construct to mark a key of a TypedDict as
        potentially missing. For example:

            class Movie(TypedDict):
                title: str
                year: NotRequired[int]

            m = Movie(
                title='The Matrix',  # typechecker error if key is omitted
                year=1999,
            )
        """
        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
        return typing._GenericAlias(self, (item,))

else:
    class _RequiredForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

        def __getitem__(self, parameters):
            item = typing._type_check(parameters,
                                      f'{self._name} accepts only a single type.')
            return typing._GenericAlias(self, (item,))

    Required = _RequiredForm(
        'Required',
        doc="""A special typing construct to mark a key of a total=False TypedDict
        as required. For example:

            class Movie(TypedDict, total=False):
                title: Required[str]
                year: int

            m = Movie(
                title='The Matrix',  # typechecker error if key is omitted
                year=1999,
            )

        There is no runtime checking that a required key is actually provided
        when instantiating a related TypedDict.
        """)
    NotRequired = _RequiredForm(
        'NotRequired',
        doc="""A special typing construct to mark a key of a TypedDict as
        potentially missing. For example:

            class Movie(TypedDict):
                title: str
                year: NotRequired[int]

            m = Movie(
                title='The Matrix',  # typechecker error if key is omitted
                year=1999,
            )
        """)


if hasattr(typing, "Unpack"):  # 3.11+
    Unpack = typing.Unpack
elif sys.version_info[:2] >= (3, 9):
    class _UnpackSpecialForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

    class _UnpackAlias(typing._GenericAlias, _root=True):
        __class__ = typing.TypeVar

    @_UnpackSpecialForm
    def Unpack(self, parameters):
        """A special typing construct to unpack a variadic type. For example:

            Shape = TypeVarTuple('Shape')
            Batch = NewType('Batch', int)

            def add_batch_axis(
                x: Array[Unpack[Shape]]
            ) -> Array[Batch, Unpack[Shape]]: ...

        """
        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
        return _UnpackAlias(self, (item,))

    def _is_unpack(obj):
        return isinstance(obj, _UnpackAlias)

else:
    class _UnpackAlias(typing._GenericAlias, _root=True):
        __class__ = typing.TypeVar

    class _UnpackForm(typing._SpecialForm, _root=True):
        def __repr__(self):
            return 'typing_extensions.' + self._name

        def __getitem__(self, parameters):
            item = typing._type_check(parameters,
                                      f'{self._name} accepts only a single type.')
            return _UnpackAlias(self, (item,))

    Unpack = _UnpackForm(
        'Unpack',
        doc="""A special typing construct to unpack a variadic type. For example:

            Shape = TypeVarTuple('Shape')
            Batch = NewType('Batch', int)

            def add_batch_axis(
                x: Array[Unpack[Shape]]
            ) -> Array[Batch, Unpack[Shape]]: ...

        """)

    def _is_unpack(obj):
        return isinstance(obj, _UnpackAlias)


if hasattr(typing, "TypeVarTuple"):  # 3.11+

    # Add default Parameter - PEP 696
    class TypeVarTuple(typing.TypeVarTuple, _DefaultMixin, _root=True):
        """Type variable tuple."""

        def __init__(self, name, *, default=None):
            super().__init__(name)
            _DefaultMixin.__init__(self, default)

            # for pickling:
            try:
                def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
            except (AttributeError, ValueError):
                def_mod = None
            if def_mod != 'typing_extensions':
                self.__module__ = def_mod

else:
    class TypeVarTuple(_DefaultMixin):
        """Type variable tuple.

        Usage::

            Ts = TypeVarTuple('Ts')

        In the same way that a normal type variable is a stand-in for a single
        type such as ``int``, a type variable *tuple* is a stand-in for a *tuple*
        type such as ``Tuple[int, str]``.

        Type variable tuples can be used in ``Generic`` declarations.
        Consider the following example::

            class Array(Generic[*Ts]): ...

        The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``,
        where ``T1`` and ``T2`` are type variables. To use these type variables
        as type parameters of ``Array``, we must *unpack* the type variable tuple using
        the star operator: ``*Ts``. The signature of ``Array`` then behaves
        as if we had simply written ``class Array(Generic[T1, T2]): ...``.
        In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows
        us to parameterise the class with an *arbitrary* number of type parameters.

        Type variable tuples can be used anywhere a normal ``TypeVar`` can.
        This includes class definitions, as shown above, as well as function
        signatures and variable annotations::

            class Array(Generic[*Ts]):

                def __init__(self, shape: Tuple[*Ts]):
                    self._shape: Tuple[*Ts] = shape

                def get_shape(self) -> Tuple[*Ts]:
                    return self._shape

            shape = (Height(480), Width(640))
            x: Array[Height, Width] = Array(shape)
            y = abs(x)  # Inferred type is Array[Height, Width]
            z = x + x   #        ...    is Array[Height, Width]
            x.get_shape()  #     ...    is tuple[Height, Width]

        """

        # Trick Generic __parameters__.
        __class__ = typing.TypeVar

        def __iter__(self):
            yield self.__unpacked__

        def __init__(self, name, *, default=None):
            self.__name__ = name
            _DefaultMixin.__init__(self, default)

            # for pickling:
            try:
                def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
            except (AttributeError, ValueError):
                def_mod = None
            if def_mod != 'typing_extensions':
                self.__module__ = def_mod

            self.__unpacked__ = Unpack[self]

        def __repr__(self):
            return self.__name__

        def __hash__(self):
            return object.__hash__(self)

        def __eq__(self, other):
            return self is other

        def __reduce__(self):
            return self.__name__

        def __init_subclass__(self, *args, **kwds):
            if '_root' not in kwds:
                raise TypeError("Cannot subclass special typing classes")


if hasattr(typing, "reveal_type"):
    reveal_type = typing.reveal_type
else:
    def reveal_type(__obj: T) -> T:
        """Reveal the inferred type of a variable.

        When a static type checker encounters a call to ``reveal_type()``,
        it will emit the inferred type of the argument::

            x: int = 1
            reveal_type(x)

        Running a static type checker (e.g., ``mypy``) on this example
        will produce output similar to 'Revealed type is "builtins.int"'.

        At runtime, the function prints the runtime type of the
        argument and returns it unchanged.

        """
        print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr)
        return __obj


if hasattr(typing, "assert_never"):
    assert_never = typing.assert_never
else:
    def assert_never(__arg: Never) -> Never:
        """Assert to the type checker that a line of code is unreachable.

        Example::

            def int_or_str(arg: int | str) -> None:
                match arg:
                    case int():
                        print("It's an int")
                    case str():
                        print("It's a str")
                    case _:
                        assert_never(arg)

        If a type checker finds that a call to assert_never() is
        reachable, it will emit an error.

        At runtime, this throws an exception when called.

        """
        raise AssertionError("Expected code to be unreachable")


if hasattr(typing, 'dataclass_transform'):
    dataclass_transform = typing.dataclass_transform
else:
    def dataclass_transform(
        *,
        eq_default: bool = True,
        order_default: bool = False,
        kw_only_default: bool = False,
        field_specifiers: typing.Tuple[
            typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]],
            ...
        ] = (),
        **kwargs: typing.Any,
    ) -> typing.Callable[[T], T]:
        """Decorator that marks a function, class, or metaclass as providing
        dataclass-like behavior.

        Example:

            from typing_extensions import dataclass_transform

            _T = TypeVar("_T")

            # Used on a decorator function
            @dataclass_transform()
            def create_model(cls: type[_T]) -> type[_T]:
                ...
                return cls

            @create_model
            class CustomerModel:
                id: int
                name: str

            # Used on a base class
            @dataclass_transform()
            class ModelBase: ...

            class CustomerModel(ModelBase):
                id: int
                name: str

            # Used on a metaclass
            @dataclass_transform()
            class ModelMeta(type): ...

            class ModelBase(metaclass=ModelMeta): ...

            class CustomerModel(ModelBase):
                id: int
                name: str

        Each of the ``CustomerModel`` classes defined in this example will now
        behave similarly to a dataclass created with the ``@dataclasses.dataclass``
        decorator. For example, the type checker will synthesize an ``__init__``
        method.

        The arguments to this decorator can be used to customize this behavior:
        - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be
          True or False if it is omitted by the caller.
        - ``order_default`` indicates whether the ``order`` parameter is
          assumed to be True or False if it is omitted by the caller.
        - ``kw_only_default`` indicates whether the ``kw_only`` parameter is
          assumed to be True or False if it is omitted by the caller.
        - ``field_specifiers`` specifies a static list of supported classes
          or functions that describe fields, similar to ``dataclasses.field()``.

        At runtime, this decorator records its arguments in the
        ``__dataclass_transform__`` attribute on the decorated object.

        See PEP 681 for details.

        """
        def decorator(cls_or_fn):
            cls_or_fn.__dataclass_transform__ = {
                "eq_default": eq_default,
                "order_default": order_default,
                "kw_only_default": kw_only_default,
                "field_specifiers": field_specifiers,
                "kwargs": kwargs,
            }
            return cls_or_fn
        return decorator


if hasattr(typing, "override"):
    override = typing.override
else:
    _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any])

    def override(__arg: _F) -> _F:
        """Indicate that a method is intended to override a method in a base class.

        Usage:

            class Base:
                def method(self) -> None: ...
                    pass

            class Child(Base):
                @override
                def method(self) -> None:
                    super().method()

        When this decorator is applied to a method, the type checker will
        validate that it overrides a method with the same name on a base class.
        This helps prevent bugs that may occur when a base class is changed
        without an equivalent change to a child class.

        See PEP 698 for details.

        """
        return __arg


# We have to do some monkey patching to deal with the dual nature of
# Unpack/TypeVarTuple:
# - We want Unpack to be a kind of TypeVar so it gets accepted in
#   Generic[Unpack[Ts]]
# - We want it to *not* be treated as a TypeVar for the purposes of
#   counting generic parameters, so that when we subscript a generic,
#   the runtime doesn't try to substitute the Unpack with the subscripted type.
if not hasattr(typing, "TypeVarTuple"):
    typing._collect_type_vars = _collect_type_vars
    typing._check_generic = _check_generic


# Backport typing.NamedTuple as it exists in Python 3.11.
# In 3.11, the ability to define generic `NamedTuple`s was supported.
# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8.
if sys.version_info >= (3, 11):
    NamedTuple = typing.NamedTuple
else:
    def _caller():
        try:
            return sys._getframe(2).f_globals.get('__name__', '__main__')
        except (AttributeError, ValueError):  # For platforms without _getframe()
            return None

    def _make_nmtuple(name, types, module, defaults=()):
        fields = [n for n, t in types]
        annotations = {n: typing._type_check(t, f"field {n} annotation must be a type")
                       for n, t in types}
        nm_tpl = collections.namedtuple(name, fields,
                                        defaults=defaults, module=module)
        nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations
        # The `_field_types` attribute was removed in 3.9;
        # in earlier versions, it is the same as the `__annotations__` attribute
        if sys.version_info < (3, 9):
            nm_tpl._field_types = annotations
        return nm_tpl

    _prohibited_namedtuple_fields = typing._prohibited
    _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'})

    class _NamedTupleMeta(type):
        def __new__(cls, typename, bases, ns):
            assert _NamedTuple in bases
            for base in bases:
                if base is not _NamedTuple and base is not typing.Generic:
                    raise TypeError(
                        'can only inherit from a NamedTuple type and Generic')
            bases = tuple(tuple if base is _NamedTuple else base for base in bases)
            types = ns.get('__annotations__', {})
            default_names = []
            for field_name in types:
                if field_name in ns:
                    default_names.append(field_name)
                elif default_names:
                    raise TypeError(f"Non-default namedtuple field {field_name} "
                                    f"cannot follow default field"
                                    f"{'s' if len(default_names) > 1 else ''} "
                                    f"{', '.join(default_names)}")
            nm_tpl = _make_nmtuple(
                typename, types.items(),
                defaults=[ns[n] for n in default_names],
                module=ns['__module__']
            )
            nm_tpl.__bases__ = bases
            if typing.Generic in bases:
                class_getitem = typing.Generic.__class_getitem__.__func__
                nm_tpl.__class_getitem__ = classmethod(class_getitem)
            # update from user namespace without overriding special namedtuple attributes
            for key in ns:
                if key in _prohibited_namedtuple_fields:
                    raise AttributeError("Cannot overwrite NamedTuple attribute " + key)
                elif key not in _special_namedtuple_fields and key not in nm_tpl._fields:
                    setattr(nm_tpl, key, ns[key])
            if typing.Generic in bases:
                nm_tpl.__init_subclass__()
            return nm_tpl

    def NamedTuple(__typename, __fields=None, **kwargs):
        if __fields is None:
            __fields = kwargs.items()
        elif kwargs:
            raise TypeError("Either list of fields or keywords"
                            " can be provided to NamedTuple, not both")
        return _make_nmtuple(__typename, __fields, module=_caller())

    NamedTuple.__doc__ = typing.NamedTuple.__doc__
    _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {})

    # On 3.8+, alter the signature so that it matches typing.NamedTuple.
    # The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7,
    # so just leave the signature as it is on 3.7.
    if sys.version_info >= (3, 8):
        NamedTuple.__text_signature__ = '(typename, fields=None, /, **kwargs)'

    def _namedtuple_mro_entries(bases):
        assert NamedTuple in bases
        return (_NamedTuple,)

    NamedTuple.__mro_entries__ = _namedtuple_mro_entries
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       [Grϧ~̡fp
0E׌ %ZC:ذBwB~=?̬CؕHQG__իO^'yu~MgÅzoPeyLlSFfRMP{lO4)T}cV:]=V;~/8Z$^G(VȨmŚEitҍlQ!=K|ՒN'[S^لVX.O3[C&Ⱥ4enG`w۪H|ޗ4Q`c_t1Ӛ)Tn6&7I߮Nu->Љ{;qb]@+W
LRT?&Ɓb΍J+|K( BH
A˝Q[T-G?^7!$IK:J.Xzd`M7zlOT=*	Y	nۆj¦	1y༙pK%AG=NH^a7AܑQCGӅ,Kg5_I/H|""ivPksufW7ɽ$6IY(6`]<^jmD7MGE_@[6a
}z
d:Y,Nd|ZҶjҟ<_j+(H.czUd$4y7_?~Yۏ_ݨ^~Q&_B[q]缞UNzt" -f%$Zv۳b
:i' M=8AnihWGV=yTG8%֔,s ky^k,D& O]ú&t",`Uij.0-ZtK*	t+&pe\5͂TN/4W)Ȯq8? \bͣ.
*҈f1'\
8ÊlJ2:Hs<W%@؂s{/vf헯_>|	Fql>#"xF+,-d$H7y`::l\/*-0le[k q}/K-X *&Wp[A0pNȎhO
L:!3ؙDڢ@ap=5aџLP/k-"60<J O#֜\*.d鰂:a_ؚzUr$1>:!~PU8l«
'c2%~7[c5K,`&7"b}2:5Wt/\<e<`6RUj6cr^{6
J/Vv=~ g{&.0ipUrP<яK8
*%-w=bHw%&s!޼Ko(:
5yQ
E}6ҸJۋ9\&imC|+EA3!L[)(f;I|hE6qd}l4S[URkdqlp"="6_20.;J}cwz
å_НmeCs5Y&&r*awUEt	ĳxՠs
db.)~v4GtYGAĝMwzyhc,>^֔ [9ib>SOf[$f .\N0aj_x [EDݛ`Q1XA2\Z]͑_t,OoΆ|xڴhqb
u_~}|?=@K3z[u-na,O`
eniWPs=XS.`8N&&=|w>]w
8GW6QӣR>ת?!&)AS)җX$׍}×oq2z&<:\t
yZ=:-0**3PPZ\c2"ܧA霪ؗo1q!ƽDq3~\lI6,4!e#*k'wf}0!&6	.$MNVluyEQO:j'A|^|39}XN,]
gFK2}NB8#cr1Y2P$C%Ϥr\Z
J<3%HkJHּ3HA ;y1xpIЇp/z	oXv ]ɚPU7oI0qұڄMR;kM-Jy@ysZDHU"  0MpW_8iDq[IM-u,sJ	mtʽM$pNR~9)^Jwgvˇ~8yOچ<JYJ.d0&,pر+͵4sԑkjfyK
IüqJ/#4Ե<՗,إUD sOܑH	Q!#8D
톓ƺHzJI҆ĭr ]ʐ۳5?]6pnB_ rt|Wa/@N> (6imF:8k̈?>P!J؍SΨƟ[&m.OQOָp.9Gd}u#GkQԚ7UIRm
WlX!b\i*p7LSҢeVYZME5{U]n+w°s>UUNT~Cx]q
IO#ќݻUWbQHLϷy7"Ddqb:Ý%nS7b
)驊4VZ#[y
(У>
]tXNj=;zRz/Jh TMF]+#hw
E+j>kg\H1Eݣmu0xn^z2F?	ԮhEu%#f-
FiNm
39Qsj}*w׃b{=OvƦSMے1˺`vfCԩu_62>8CLʵF`EAK$LTXK@J;?s1;u)k_^|imq%\B"PL<r~ؐ1.L͒0_mZ?OMW:dN,(h尠@
SX=ۢժS 3WlRq"|XU`G&mIs-Hq|mT3ߴT(&ƘǮqZG#1ذk$[Z1aӐHxIGK;Kڎ`3RZa)MdsCz21f`rzBj]S0zɓU)Uu":S}=w5>PJ7<TOW4xPHdm]ci%׷nZ돘}_sNAqz;x{.M0ŭQƩB qBѿYXtVst9]>ou,åR
DDfASH!Cڃ;(Ml*a0.ZQKJ&h>Iy5ktФ5=R4t*iB8sF%걐(M)RW:68b>GdZɇ-Rh	w>F9>2ʬB W|zʝD.[NiK;wD};3	M
|4'BcfJnV{!J|J2Ǡ0d<Ox<Z
XH@z.;VѴeFtYM㼝qPZ7E|iV2d"
 I|NƋu{L{|Xo~x|_on|\6e֦b-^d&[ +: ϓ
^ƃbs+
sc<uяʍ'ǘȺ	iO7X FCSF`4<#)W?I{y!>JiYBtZL|1@؆_ER9BҤ{n&nT3ֱ?vZzQ5;Z{F|nO$ZrIJQ4pI^7ꏟЍuCZh=n7+Vt
#u	5!rvc3	~^RS; Oԭ3\[r[R^`G	JS!{7ե(nȦ w*,}+\s
1rÉQ%ӐtMpZGjtX;2k`J~	}vl}LO7dWë,'f(nfp>Rw:s>ěHq-ʹ|;[,JuG
j)'[01,CJ&Mv#i ֳ4ҨY٢Ux1qw
R표mhG!"_X||5湑gv:2	|^<`8ǆ|º/4xL"*SkG a&J6 DcDsޡAB7ėnM]k
ldtĠ=YtH_8E$XJ8ұYlqjHL8jh<wo&X<<Ѥ!,WH_n4?O&\
hW@+cΑVMY[L.όM&><~|Ͻp'{s@$G+_Sg>2`YG]Q^TLZu*,iwj}O?uL=Pl{P $9<ߖUqIm1	u$7Nﯯ3Qljms5	(j1ήmtI]yg"r@gT^cQ97S%;cDa&ćZvV LlyHyTb%\9O;1pM\krzw4xg|j.-&d5K63WzKw/dcN{)2X#D!
Ĩ{z4	uT"q(![Gpg}'lA=eDO
QJy0]N16D١c&yH4&C7ڼyBkH!|M+o+(AG9!whnt*;?i85'Ej|ӾF
4GGA|.8$ʽF>L{6+ΣLN_z8騱uf(ܬѹt=˨]'~$Q$T\fi%榢|S۟;x7|VݽQR:=k1VX;.Av-JLJaMBR1y+{z++k	lsB{wr.5YfS9KŲ\Hl_QDZ_e9
* &n3b0icdn]nGgh:$"YkG]U@n=HD|ӛ?ҷeߌMBƜR/W>$ Er@2ިdGu@a߭ʈp#Mt0ѲFF_\P=ժn^i[o6&G+Adzh4.rQ&06X5an2y?977ŒF:)wQ9&JXJ\5R%ĽF\kZ#}wi[}Ijʺbqu΃0as)tb鼝2F,T--up΍.v>ߪ>mK0W;$ {Fdݖ#ӫ, @
Ϛ\{'s%DDfdU笙o^"	TeeeF3D1hRvs䕽&q͝yǽ2KBm2W}M#QQ=C
.҇f,ؼ.ӆ}p
ň0^K4JKwB1EMZ
V]N]̘y,.. 3A?rd!A9avN00!Jaؘ;>&]kJr8کD=۴dC% +LnZ%49Oy:;MN"4yk]+T9)|pHU;P]8;sHh;kJإ6ay!L)z	4>e[9ek9s]a+ˍ`sܒq_u)v"z*@K}xd;^=$Ƣ CapPiw˶帡z]rG"_!'kM2zJ+D	!#׃EG$NO/(ջmshqFs7bۦ4 nږJęr:s8]+2Pb{ATɔ(bN%bjC!
	?{{O#XWZ^V$NqkcA/9q1>vX'nBjk{kg r$QAhrV@ݿ[ъTmW2dՏCE>Z0TOPˬ}N*E r L]>mR`N
\{,>\s\QˏR[ȋvBfWO5}4_p/KV4R"p+:V:K	n:L1;DF`Z:)B`"Q
& 9 z?`x't5uEf4\,(觃Ŏ	#]nnpR@x4}?c~a9̫#aP5~DIt=[Xxe^M=;68/`lc;
_lqC	݄a)%pPܺ֐]%N6'5J͸fLZ4yx]H<y;03iH'2HV:B=B&e.av	U?Iz2B-v2NϸuȨ'99G01<`䚉&$!ʇ^o<_[	kmܫ#~sGZW*
t{\[	ٗ[8Żf-ۼT#t%-@n$kCR/K$r6ն'70ʽ,w a@iq%hsy~EjrPh].`4¥p\|&Hs,QT]K=oEjHC@rΆҮC=e<'d)։xlpXP/t˙1uإoxtL2t,cr`ETPt)SNɩvwˡ߲
JP|3r\z9("?ܶD _GeA0ԋ9iՊܲ2	oo'zЀM͠U?
?9\t> }QxL\mȩnhk õ$0Na,Y!Zk , }M0*J]mj"!LFlGo!]+DNqIR/
"Qx%dH	DDLC\"kڙޥ-5<%A-CizߢDj d8OQ:^ސ*Cmip#6	.hVfWkn%{	w|)oRGH7YL(fŕ/r'Hsm^W)AyýtMh֤NR;«O;79R9y:19#Er9~?q'eaR\0&bL@2;ou|
n< .]3]gٞҗ|˨Omdketx0*,R3?h qp&9_tP]5%f@P_=SD65 k&(!URC3PJ+/x-eb8u?2V2Sѿq[;o͓Ԓ{J5=#{M
x}R֢B_;ryO>"QDBaFq:G[>i1r1GN#󏜲OisJ&'fM5O)F,(2Lacصp3')ITk	Gkv,`dh`f&=S`DqM[3h2I}Hz@DB#aYan_xsM\VV~?l; |FĂ@D:I i/k4HR-y_xS7z]&/noc7Hډ͍}x Sp zvKެY& Q!cIaB>(9ZOh.gvpZpX\}wFz9؄
Sge )[T&R;,
3B
MkEAO@MfS#@vL} NF
mU0ɼ(|A632SD޵ER㣿]ux7ΊxCѥyγDQɊ7|pA+Z/Vݷݻ	|!ZQjŀTZPS^kDФ^lZY(k#hdZy[OXf
On's$sv
Z*c LD񗹋]E}֡hS0t,jI(W>ZބXn+%#	AQ>yԕ<E5bI?KT +BLy<.JdϘat2kٶll6EzsdĴxBXt)׻yɂQHÒ\g
t
z	O*;@hJM{ω}5*댞QxIAs<.ѱicUaEr&>
q鲝΄-IlxkqB97-Oȗ HagDJ9^wp1Б|@KpxT`7Tjs,\cw݋RkD	 (m@9<LReKo˹V	b?{~՛o??=Sfr&Q ql&V>V3.dP%TFb:%B~xٗ :=
J%V&MqֵKI3Fp	3uLuFep,]]F]_P&3y0åh$7_p
Nu9i?]vn+*_69h\ݹtP<{M!spٳqgΞ=LƳgT;6FKw|h|.V	#xaۀi'v?$}akѥ;Vv
jw(+nV|].t
`j!QdY	A1,ͮTD)dLyEJ,ٳ	GWhU~S|nז<>.C@h"Ow4<!"ƽCtekLj *i,߼$T%=ך1qBzE2W1;ONh&tTG?x틾eQ0g&diZx[j )S|%ʝ-#ڦ 9ɡIF7οI0Yju}X@~ۚ}U.%\!1kAO8F:􆀝>ic$=ꑣèLj3T3Lu5^SK&Ys(`Mk-5~pW>;Oi^O&v(Ľ40qy
pOYLG]	sPml}K+UZE
cOPH9	X:'bL+tn Pgzw{Ocl\X@}`⊱G"l\f*Ih-zdkq/.3RQ<K@g%w^gvFЛ`֠!t옾tg2YϮEX3wغ9S93kI'}6W\wH
ÿ K Ki$܎'NkORm4
fedE7Oԟ 4MaU8zXREڽmL8<-^#ҒS	qw0+ctb<tf2+y:&Oj/`Rۖ8YKdj_CFI6Eڐ'v!;W*<d_Ph!k3`hI).t5@ԋ6$f:aQE츛l<r?fJ<o|F-PP9G9Crxi{y(*@YTu{q0+&qo[.d>}p¿d4UHYԝsmZRdHB[vM6-i"(JtAݞZne5nogA*@å-UZ}n+怗ZJh5B+c <mlsS2?I}Ft˻Ǚx1sXD "wѠ`TQeLA	-p.\ -\ajXsoHV;SׯVqq)\~
8<
W.uC[=}O
;53=ʅiԂ{vƥõD.8K axk6
t}>k#HUU(;/y95KTD"rru5#t4.E@[1F
F=2{ؒ}tBڢܳd &$Đ+R-%=>%fsv]l-$tz~| $YVK^OL^/PAŝ_=lޏ'k^Nl9=cT<߹W(h
W}d~H2P]gpH.y*kad ƚ*(~2}U %QȌ^Coc2fet*yѸq-n%6],3cFu@,PE30-T}3AO0' b)k`^{& z4 HrzRJWsxd,"af$Ja1ѥK\c#Sk0y_mBHaIe3X%4s8uFյiw0{09nMsVOc:nϷh<;7oq]D`R:߇4ش'MqS^<ypZa(_S,a4+{g:dt_jiGmaNo|ѯDZ I[KlԼ{^r4^fltE+qΈW]	+ 1BH:#W|Yiy/ZhH蠱v;Sbm<Dy/zk/Shvx&k6t'n2~۬<LҩFq3ȣ3t+4?IPn%$Pە }uc1O'[yϽ'tO&A=h-{Q=\a䏧Jzq}3[nyhl"
D~ݹiz;E~JRNGR"dv/xwc`k4]=T7:a|SO" l=u
z :G@v?g"M!+wj@COnz#DmW4߱1}\#Z:dB{>sCL`Igr)D}b"YcG0b*ݤsM-F
<1F4|4zAI(i
d2'YR^obBP]G=RTMPҤXPd02f	;uߩt#;iZaAaykEIN{tWTcU@$?=
I/JL
]!(ѫm.8I+S	>NܒZV<]Cn3H!MHs#lbvwRh9!pJw6Y`xT)'EB05ie:<q]JKdr:OtkSu4@G7E,;nZlP;:u8AdCԛLQl1'!91'D4MR-3Bj,۔bxr˵gN|XpZ>ƽcJ't醌+8ҠSM:Y t p:`}litIe}mPǦX
mxfuϥzm^OB2>iV U ȯP	|FIݽ.Pѿ.;_SP9[Y+9r¿zkf![ &I]8@vIf%TB"<C{LjGFS*`)։ R0|=ԊijE2ZEߜ.NeԾ$<$H=cqpf/?I\4Wlٻ&4_"5Lo^l\ܜ7*޺<<7k7	)>&=)aJY|M9G2'+EܣD*Gp/GܦKJ70qA ,5盅OtlLɓ d2wH)YG9 VZJ%F"Μnظ;Jy¶dnBtm?#S&&?XN*=N^w>\ŢLǗ4tdx؝-y9yHlNhĄx)ŗ>$4T_.N|
	S6gX c)ˑ7
%) ONuP qܭ)	j}ddiŲ+<ҢZ\IGe9KÓvEy* IySګQB.d2G;qWq7v99\bd7ikLMӟ	$|	oV^V8u,W2L1Ƃ1%_id(PY|;D0+u]SBY09LHe#xFAdx^9IgIo6_iN] SgU؄t@v{T;ǃF5=hX	&>5dJcTߧUPN7y}kzd6K?tbD1Ɨbc
*J 
&~G27!#\	K
ۣŷ	uK ͭ, =/7e7y'wOl5#{Qg6\vd1K7
b1ug3wV./R5{uг!/Je3鹣7dˢIlPW9Z+2B'd[,;HKsZZNzI&[C+|Γ	p1'noЫ:/?7F~3W00oלq/x0+DW.&}hNހnGt%x碮&Y|'
P"wtU1'}PEof=%3&~9z/߀%"QklL2ݢᷛq=
0KC͛SVTCXxKș&)wm~9(AW;IbH|Z[օ`L)/`a\+BgBu]jf폗W/i0N"?V=Fɀkq'}$!)?Ɏ,ut\Uh(1Snr ,p}D>(tA 5)N D;uJI#2u:t,L!	nP$Y(pv$.0ٳ=kI4a#>eQ_OsAa.=癚1[,l X8AYvF(1緿Rr[.5ud>iyl|1]8ֽt=aYybgza嵐׺
{0%`,
gg(]-8'0_N7|:nH5	!~/oiIR^"<|]<->(cAZ]7FWLPQ
`ܓ{sk[m8):Zz : P@}rF/w?='3!'XH7H16!}t:S8yVܛ6XgEWxF7bCqDL!US?7(+KE;nd!>֧=c=-,p34p'NU k)OikI"שM Y-mj[5k$ԙۻvЧ>G-b	|w[	rFUoa6T5C!NG|NTWCrID*wH&~8aW^@oPq_k"tt dPp-^`w03<g,<H2nL!}/%rڵI";[XG6TψO(p&h=~<o7~s'1҅12|>=$ȷzBM=3({5P!3%p|_-^׽v.2!}Y\۠lw])۽{n7ο}BBQ0-.-ƓyF_ PpQRyʄ(kS}2+qx1"%="'$WDOrQ},@t=A[zkvk'tt#CK}S)ݻ1+!myݮ=6۪rh<dٽnƛ&ۇѠJܩ|/FDq2o&אajS/jY
zqJniX(}Vd[(5[˘.noL:%,7nɏ-ժ9]$*H:h=p9n˗SY'%;r9&\x-(n	jhYW;t(w)vJƖ~0>^%o(<]} [>qi]feTVw&smՏɐRJ09[sD1?^LFf]_ͦUKHAXtẖ#S&bZijaƣȃ꿬Ra_Qw"PoH@nV΍vp%j@&wPdY@/fRC~ٵzkZL?Lo~ᇫ_	
f)pFgѯU33z_Xixp[FB΀W<"V>"a91w%V/^CnVeכo^M_q_tdu\_6#:V~zE.$WS
<%J>8WD\3`CF>H4=qNݮRzX7sW}yBa'b*|-ɚEA%c0L\ŵat"\.م"T7y0'1rU^PN=δF8|*xP^(mƀH͑KjN
Ιj6htFSioP^7z,40S.YjYNɏ#n\%VH)sfvJF8rWYiۍư]LʿPQ!.;غz;f&kiAT_[fL1/wį͡[Q]PkmCΛm(S'ރW@FmTx~baR{U`ISEkJ}u I |Er+Wa-VVS`صRH^|^2hc-SE g>2vk]Kh@ޢQ3! S
Yk8G/>Z.S\}bK<P(!ylı3G؏z'Cz(ʧF^,׬ nr*R"TucRb|W
ݤV =/bH|t-)>&Jk
Dа$E`#KXѽl_֮FsU\LV(#ha[^lCa&Ygqx4*
F1ob㚆vEdR]8Cm
Za-Glڱm$9O>c@MxC竗˛x;z^?Oo}p^woiH>
˓ܿ)U¿p{OV?&ވWbQv\қ@+X9ûtpsP.N!	
Xx_ kAuWȄPscw{{n;,Jj%8mFdKtH<לd
9sAFGONUHDdrrX$\צ :o#[ ѭymY%JsźHs =~Zea6Gp22((hw,%SjQ#O1:@e͇CkV41=[ElFI.(RVJ`¨ϻa3:gE'>0|/T9ξT6Eff$5	V6`S-
uȟL&
WyKɘ$ӌ-DoP'-+_bjCq6mu] sTVڠX)A:kꟲTDv&oޖf"׭kF^(%plJ<߾ږZBDV]Xdft[S
#c;M-^>0~&Uj0vdǽNDpZ;FxY/ӽ$'
ydH'<]>Fݫ[H[FD^XO}C4<LpC/O~1-ˍʏySR~tS=zõElC)0˲e٠e-٢w^9X>%3Wxn>EEK!
K5363	\ܹRVa6ދu@ p}AKĘ|&w<^?94kp6#/Z!jU"Mo)G qnic:1J~_zzʕ׽d~c4nJ?wǁH!ZVj"PP_V}[J1DK]BήgzsӬ	<|nqDm0tv _;)+Y!/-27E~'d2<vD,J	D&FX"w+'0ھң́
4*C~
Ҡ*c vgC-"}k8aHE2~&tѣOO|L=cMI:DxSwJ~!rDjI-xV<9c>12jbOt8S\֗N+[}4SGAS -Ш~0?s[)N ) s]'hm%!_Mdk5RclqfK1ry)zOwwq3qOs
r* ˿$2-v9	ümy.DԢYCt="]5q"r3Kh(^rSv;px^6:ޕJ?tz2z5vJ4DH	jdFԗnJ	jOYzNZ6_\VҘ
}P^SwH)gZ)UkB4Tm8t4Gϒ	@3[!IATe98|!m8
=A:sɺjƲb卑[7G˳gAX4?"m?X
@hz6v7
ڑ$LBMmyY~̸(d"_XHu~5r;64!Kg*kF_\7hz75ř`kB;%>	V&zL<+iDpFvrT|);p$څRI.dzd]Jv+6#̀˅]OmbRzA|ӥdT[{=.:]^!*4`_
fkzp{՗:lw1)a?Ja6ES=7WNQ^a-eAe?N!nuQZ"aӖ?A
̮NG 8{$B#}_Ք:ؚ߁NnF[w
7=|Hv0mt696e	^m;v!dmIC[;tM8'J>_xD#a\-̆-5S뗣,nt6~ec.΅8ϒCևJTTM^Q(?^tA[6WAbC)sE|J,dT<	׫	G@0@V=oc}]I]1ۿAZؔ3};pX_m

I MC]O06?
Q6-,llyqk~k<S_Z\wØ4jq^ePaUv\~9gnO\ٮ(]þrkiFYr
Rwd*t$P}M<
)4QLدVȂY.}N b5)xb
ؐ5k}uqJЌ!O؈|m8o[YuFGi^1^Ș{1%طѭFr{lx}!D1P3cj#FFW6Yn~re'/^;;DCR"m7~ӟdfc|#G!e3ۙnǼH|]ӣ2;_lF0RϽ1 m7~0F@S*{f3f--9M53ZGxVX8z5'vF`%Ar"܂c*	
<4/P5
R-a
}6K$dEw:ҖDI
 nW ~IY
ѠW{.e߮J)f4!A5^(A@;\)<yxJPD(P6F<ӑhl(Wjo
*bqA}X%
xc{P>+k5o0#6ZxW@eL,xAE#f)=;C٩~,޲x,έNM)3}Z^*x3&rdAʟrFŗڣVwY-mx6gM2YDEL{/vLw1+IԽaԌ
iye_}]0SES>qA8DJf$wdq)OYcxgۀ
Fzñv[\%ELOLdK)oud䀬bU
cq@-!gZ995BG1 ySE%36ыbǰ̶B=^39o`QMDabɰsPBҧU>K(6;_T2VQ!t_g΍#[Ĩ
oV=W+6hGa誅"^);!^wA2@On@,]qJOLnZ"
w	{:zAs^\<A,)9x5+ɗsl'Ì5_H~rדH$*N%#:ӑES<.EM|ĴdG*t7YP&O1=Z$ P#%6>T7kC kbsG\:KU)!Pd̝CQe8fAl;[LllX@
"e!;#>woIgmjka%5E\+xJ^1IH
:4F)TH{8\eaܽMr䓨xC[S!WL$:uN:fK1FfWUB D-,(CXo%730q0pxօ"4Lpٞ!	 	 }*3<4"VNyF;'6i=~GżF=m3]xͩ:D;
pxKXW̏ dC)i<xC'+tM)Mw^[%\R>KY#c͘ĶV1ؒˍV0`AeԷ1.erFkv`ԅDexck^3y9쏧mj<;??q9`-\EMȘyjh#?oǝoe>MVM-%
¯[[*4M,^19LjD
BK_4+L藳<0j'aeu2(*28P[keԉܓ=* YЇ[Qsiu{_stF8:W+BZ
&մ6}J=3fqBD
y)iT?^?W!x	>H2C<@:At! o[n>QȖƆT7b@>IE7d;ڲkbOy:OGA7ׄ$ZsMk(ڱlrOp#b2@ɍ%֛?!,	G-71۰^֦f!tU{\~Y8y0AV)S&ճ%QJ;*M+r1ޒs4?r[9EAyX+"9焩UHCyq5m:P4IJ@vѢA(#B</K)aK8<qwU<L u#va|;`p0XGS	(,
#řጮ /RiSq{PeqhO'N*b]LBWW:8t&%&5nb񰦙P+>JzK߁@RuG_sbwyK UmI$w`OSeғn΍,s~R3i8y`́a<ѢƩK˦o+38F;X	$R[C$U (ؙ
V5ZU§iA
24&2	D5],s{{L6j2d(U^m[m!P?(|@jk:Z|xHzsjQǔm
_?/>$P\Lz0# JvT#}j]Ose|dؒu}07jǝ&@So)t^,0ޚHw~\c%_Η|"Ug:/-H^{M/흯۝.Rt]Q{a3SL%}X*uEQK2[֗2_m/MН5}ok`?+! wK
]`g-P93 UG|ٓ?fY.#ŝ`5MX*{8O.MHCIYlM XS p,s^F}uV)R|M6"|cZzf8e!FB<̮W 
ce+yK΅STfKt{
pJ
tRB$
2
o;$mgG\9^{	\)ĭU/C1+_d_m|7"MԭfhC1+Lk]8KSF<
fa!"Z\NIWn+rһђW:pO:<f+@m(Jz,kL!8et*ѭd<&Udno1gmllsnU]ydf(Aϲvj{9ʙIu
AtmP	-G:꽻^#SIe2>iB'AvGsกeh ,uFOzEve(?sں.*SQj2>S\}s92<FvT]vb'#FUWg0x\;lP'65IIfx0WOv&[<m0f+=ձVLc:N$EGP_(.]5	L:3NMEy ²4hVh_{)y"2^\i<g2iCEd)gE*z^Ş@g58WL!6Aק|-/ #ӝn;B4cxeI,'6\}2DU.45ɡ(	0smBW(D]LyH<?K]1υ&67C' ]dK_
~m뼧X$qY~%"t4Xl԰Lx_;%x|eRqG_̈Σ6G6D@Ax"<oWJdAt31%2.d(! @ytYԢjFi	3t`eA`B#s8=Z骧Gpېit9WCSKv'pqp_vg 4x͟>6^|,.UyGLA_1@R(4W"FjdT-"_Di6<xTLm,ꦼy .Hkȍ%
ǎ_ֶ7jI]X:jYmڊET̢4~8\k6W4vܤEEP +\"b3隀Yn/qA}۷"UVL{t5,kg"/9F cT<+z&PG!h1jmt-#$}=q.`F]ixv4Xk\<0ȿC!<8O]g{ p	wڑy"!"woz^`Dc<mيt4DUKm,z#̾<?סhS*-+v2I`NsXb٠jI%0*&_giVPp6 
^EKa:9%B)^ :H4]
~dG5,8t(;J`d)?Os8_U^m b4Y(=R-HP~Ɖ=~zqׯ0c MK
'e~(n&dy<S(L
t>ݔvNQ2=&GR;KR@eYuJUYr8(l0-nGݺ*)l1ȃfFd)"ay8%==,
Ǳ38z«v-)E
Kg.̖ k4*ʔAj.R-S2xN/d#lKGF_:+ET<HU= L\NeHS /ʮH>]܃1&V7B|rGmmhak]/Do~fdQ<0M:gca{HX $N,^c*7\l}A/댼W)	]2aUПKB]TԓGL
M8
)d~ҕ?
"2wr?Q0|AIz;W<iUho?Sb&ӹ,6zrM]A{~}4}5 CqE>`
g8
:%Sm3Р̋l
7V5ӗ'D㾧=r] P.B*_>КD.|Q7ݎxҨ.s
o"򮌂5UʜOiN@ýO,tM>ʷP;T;q#hįW>\,qq=k6/'%em/],HCcat:\8z<lKmq}y+EkM&\iF(5&ϏGF4
W>>T[歲q=|GޖdUvp'0cwTJݬ0<jT<|eGdIu6$7?x1{|!>_ T7/YzgNE'O){n2LO2
REW+Vg"*hXd
Nbs'g 1.=R5J;
7TʍO%o\1%nkl"{ȈڠЀ/ɴ.$%Z:8.u3OnzA_3C>tHrkJZXi_mzSN;E^&řl]rq8sB
XLb|ا)zWlxFN_ME%NELQnE}I]'[T${uُc"zߩ?K:j!B<0(fOx~F`=犗[3\[ÀV_D_q{*!}\^
;Il8--F	BJS.epB)YE)*Ԃ({)ӥj>up^,
VEܟpCx86V-AFדltFNX%Ha:_^ܼeqξvFv $PO<Pv#I./ݎ^1:LI͟Do`224򝯰h}D[
Ž۹Qܛl}d`V.їMǐ`
3cg~7v|z_A4!DaEX-3e*po4R2}䷷|<v>$+[|ߢ#vnnH楮.aQG̦>;?7^ցڢN"4vG&B
塚ŧ%@0B-^
@C"'%gD&-lP	VO}Ta6ƸsM2n`MV'#_BWuV:_KO=ڃ`Ƨ P%<ZDXP-"" zJ){.vlC`P:zTty
g5y`Eq+5 NB*1+юnZέ(?[a~.^P#I`@YWf dn#XU?;moUr[¥XM;_$;%r	w!Qi&Eϭ1k@?l&	A9noկDoDiJauk.nuBuZJWgz7X`)5p-Sc=eeiU2/V\cUNMǥ}KRmV%-$h{v{~)Pp3z_<_y c&"i%nyX0TgM\,a1E,蘫֤D}n#dS''>	&+Ա$QǽBaJy(,%	c-+'orer@a:h湎GԗOzRPs{pj!}O+m8kdTj)AEZ%lp^N]TҞ~&@ȕ7θb}^+d&|-io\2tbFbJw$wϿN0=*ĉ`E}hT0{&}MOpp,KRFpton*W-{e,ϐygP+3\h@r#BxOPހm~y*EQBC1q3
 /+:b%FW?kT!j?qa-l5ݝmWtcz㔪̰pK9 ]л67w2gƝ)ŞBT6DTXc"SUR|t}h`}p6p-6G+nGkGڭj(6$787\˝,r&C&Tf>NKj |˺YO6Av9RhKA$xNI{_<;s=FϬhQ7*J.r*pM>}AvDA5la8hљ;i9|~+j=p>SH_Dd, (")Nc3+UBPkqYEBil5M4A"_"r:Nk#Xmz
ϑ7 _qP'8NCa/儞	h dc7kUF_gh/N
<ЂPъ7N҅ؿ&`0swK=tl:e~^Sճ|ihML/3l*<[Sny[TBmFz$
/mIB	 6s24鳄CH޿~k;Vސ4dAlX.S2
@o}8 Czqin.,7BRi_&f/$v{$Ɛy"Ô!syGlGEKĻ8|#z,5)k *i`}#> C/ES_Vl<oh~Ytox7B;d'f޲IZË"*#!
6 b^,=aډj8:iUyu?vkr0%5lZ^ՀsݮprFlBšnNJ!鎲BrTfly҇E56DsASTf2'WiگO	7dWf` %9eRsB|IuW!4p|QÊ_^ it]4qꡨiv֤4D
S^ybkQ!CJ<w_u)6峅fbv8-uYՖ~'|
J䌤;ܹ[#ЉՒ5-4ۋv9kQTt<{͓`<T⁧a:)T9RzMV3>mO8mΜ+nlEuG;<Ǩv5CK,{gdթf$<$u?v|n]BVht]1n(sj~|yr
r=L.0Q4N>2i񰵵FKPkY>(x<*2d̵'6+z&iK=YW~Շۇ/߽zM55zPA-BDl^WƏb)n/iVqHsWd<tp{{URGoڻhWeT-|kKc;|}{IziZsYJ$jK#Qaɤ4Ҥ]ݣm";//(2J5tm!
!:ݭVoXQy=C9e&gA*'M$tfL*nHunX9KQyĥD@TޖۄF_vs1:@J
Cqeh=4jGb1shX]xۍbL1k9&"C0:L"~t8dpq-.2[m}51EHʾ8U#/-`fN nj-JS١L:u⓵CZԳĭbknA<·
SpMlGXp>_'.Go+-c.$5xX#,kEt%t-К;9K4Ahr6J̥"(,@ZM5&!Z.Dw
=eRE6j]l2Yh\Vg@Lq,o| "^|/{|l}=ґx*@Uk"Z=iA<L/_^rGu
P63N~7A-az|@bX5uF[$u"oSy*@[*=|0V=ȈVl2Cʑ&다k&R9?^Jד^lCmm%T?ӂ	8Hq`r"aDǋR71,mߵcjSu!pTYUP1
MA^T}m\lىH1-RTrA*լ=^ -m	uM`ND]0ހ(/8F.@]
]9C@zqav5DjnkD<0C>ʚs[u=.(:Pc`vy1d Z ^
G_t.ao_lqgј[M|OCWa/vw+I4I}3ykPVy
wR.9x=}࿈4sٹB{s{q_M&u׵>Ñ3He,};&7N6Fֻަ|<@uM)~`W	EHB*(acpEQ'.=|]s/.SdpD7T
 MoK5N]Hg7-K
qG>[H.B!;NXv,u3񇝋oȚ_
0N:8HtjSiѶ$U_{y2zry|n8;5g>We0MnxvX|$/pbGy%\q?SaI6>+߀їO2aql[3LSF,1\@t !4:]C#YT(Ru>:&k[*lDdvѼ|.p{(.Ʌܬ-ZajhrV.zAOiQޗ"C#ZUB,J
3nm
zc^xZV+ ZxmPj̔SsM8:]B2c/',-rGI-%[dr
*"L&l@ht;ua4aa4Nx ATR%>W&}MrYR{knN`YkY D~4<e`eY_ǙaNEŧ>9m|'
-a°E[.Ͱ./{t>ؘS@yyDqڠ1A頺/]h
f!=v05Tŷk	cX" }WPN9a5g.	Ζ$E ĤnB'5L<,K	x̖= >"xf Z]i\vPXY[w
z4ۑ,8mQ5y]n"|MZ\3%DOsn8G9t9/{ ~ koi52K/Ȼt9{@A竽'j<'J.m'2ht{ f@i)ͫsɓ=4tڋ$љ^]˩{CSB<+n(FfMVz:,APS\K3Z:).5O\&"b#
ﱏ,\)K0c*w j139ؤP9t#!
vgR(PT'	c1!QNvUxZ0*ⷪ,RK\#%UL`ߧvbM67<Hv	˩A	m%l8_dhlON#d~O	Ņ2$dLRUF7%	m~m [V)FoMR_%M*tG1%.MW'@"I|O"??cu(b2Ħ A%JՀ,f"`O} HH{"qmx}ӿb_өT'n#ȭL.E10Ggm1b{>f=Q%Eow5
%^~Vak.ifwC2mJs.5Ԯ~)εZssd+t>lJ)|q;F$<ۂm7
3٠#2UFo]œh,CMЄ$_󱦩%3sD]bNW {BN3)#J+/.*i)n,w;N`'Jlr*Hr&6F˽ )yE	S`9#y{=IkzD$m~gI=IjX=M|WTRH+M]D>_7?ob߶.ܢFՆVaЌr3,Ʒ6.ub"M;1]KzB1A)/5%
!Z	0_ފz;IM7%D7`avj`\eq<# _:M!]ÑjHn9nGkg>.~
9DHF{;`+t=+Y Q'.~[6'4?_d
phFDI(.L'V͠G^NqQ7-\f(@)doQ1epFÕin/+
,r<#׌]AoD39eM&Hs,eE1UAho춊a@"q}:3-y>fvYB|cZ
v|4cjrZ7hDy2*hdr!U}&)JKkͭΉK;nyTL!wi ^O_wbFXkQ-d{i*R.nZ|q_]K}o#B\-sQ>æY"{NOk_~m֫RP-~-rL1
&[c^%PwR"q뷛|e
 =h}RzJ-wFCtf}zvǝLYۭ/s1/X]PUܢ}%[r]qaMˁFq=aᯰ,S3sg߻sS؏*i6H
S$L`ELcűvC$r#Vx42K$`33>ΐ蘖c.[I12:y+nqqS|pdnu>1/uXAr@u'OgԎ"MOS<b*?}bL{!%r.)Ź_!C0
tR%v2${Beg/t{LΉ6OCu$4/^̓;>smo$ٚQ[		'xqSbS^pAH+uwN'3
 hay
;Ͻ0ik]7n$2i4l$_8^ԧ8uJk" M%~@-Jؐq.LeL6sE(i2ޠ,CkGCdƼ`0ַqc	h<h'wƍhFN]eZM^0K&~wciȗCB_ S;D~(xtiԀv墘HtӦ")pf*p[tu'!aD`/ۍ/%7<O(K]l~ƪ ~An3'2Ĵ_-׾#a8$=YL»,ҘB?;9bj8h-âq-mP#r$k!җ3ݹA(N	ה-пC=%d=cl'
OT=?B5}'Iw5,jpi>5}*M奫jׁҩT6e-ZA8Nj\>wgp/VOȾ=$#Pr %(7
ZEYpWl[Gdm	`-$@/YlUnAvD
TgC4yj54,ߧ-#!2]5j[J(lOŨEMdjK#),H0GT+/@bDUݯOo^ûw?L|x߮޾z˫^NͩVc<o8e9Ud]]l2tG%GٺsfCi|AC&$)Xqa7),54Xf-\ՔQkj?, 9kJ.Vze5	KH$	6F:&`du#gN]ή0j'7N4GnrNr"dR,LTCk̿@\DRZu}Pbk IbdEC TtSּ,-2j6e'WmƍjlT\l  ?};&\S~<RYA9	)z}`OrC[^&~QA߂>h³ו*7MBwUIѵ۬Ǽ1Pvڎ(3LSΆs3"q(vkx1,CjnK/6{%}jfmSD 6^orZ+]m3@؟/&@0}pݡ'@$CG o1	c|7/|TC9r;~u_䅔C1H0X,ahڔ >n[:*"zUQ7[7?T adp!ZE~}_Pp5PKIP9 CbLY/khe_E/7'mhRLm[rr6a3.wX$wT sR4ۚ,/ͭfAd	9kꕸT!b	8lpnX,)n.H>zp䕐hhh|ܨ}KʒSw>ֲFJzYa!	XM M8b{ވ*O=w5?%wAp臄]S%q+ӿ<3.a}$/I^㷠YK,RH@H(=p=#`H⽎+Ep  Vi]B}Q1Ѹ5yL(YCT`> eg0di6
ڂYUO_/(\ܶhem~J;c*J#zn
U}1>u]͡DF꽈-^'F߱iS\rEePw8kPN>p:.e6)a# 5Jdhl>75̾:++w7\DfskVNPX&s10L.-Vf4xw<a*<$`VҶ3;^ݾ_fZfK:)Iu=+̓M_*,fzWNхԞE&HX_6^_䅭nQ\2_ԐZW{* o]mEH?(?n2>|Ù WglM)p?<bj	Hpr:Qt^7l]s=I]Ru>x$ѣ9j~{G9gPi -4cJ?Lo~ᇫi|NMF W1$ܘh[ >P`%aV*D8
aY!ǨEu73 |	Y 7(i94"P~5 WzLGsZo֋G}ܱfYH/h&XDtHOQά}-DjIZ	;%/5yca2"h|K>^|d(uZiQ ?7^
`ƜLM
/Cv>ɧ TYѵDsrn=z|zČV$lC<H	; \|$.	*Xg^JtB>jajgS"'V+ݽh719"{Ubh.X7W^NҴML/<=φR$X)_%E
**n|M> aK zC/x
>i[yncX7u}י<WSW_R[n2젦0ƼmI(
S=)0pVy_ vܛ4;&єl[1њTQ	1aio=wtGYIV81e
&O7k_W/_aFaFSy)],{zcgDV2h֒<)NEoq	WhI|STCEι˰4OY3:di5}:VTɿ&/Le|lz=̵8O}xYsKv Ow*$7]KZNSrUai2e8#eZ Y7HfW&shaG
oF}:/8RrὌ7=Ta+ _2\f?d;@#t<cdTj! (D *EMHK7;&'<BzL=˹dn(Xj!§$1WTXE.@/:'G([rr7 NC8Pqc,[;-PU
?G.Q~J !HSIMUF"tC2\xɾr+)?,U}~XK8*1?@_涹Y$V49L#5
؆! |&TsxܤN_2-IG+5z%{E$lx4⠭4mE=0: dngbW*5u
ծxѦ`<&s=KA>82N	O	)UC6ȳ39bq
U^00I0k&9EGuGgҚD$j#0@Rp˟^_^'Fݺ>޻!LiY,d
ZFlGE9&͝)o6:LOBg.~q?aJB 6PQu6jvRBqΒ 9pd$s&AYI S\3 *zk\Hj<cBGmO;:;vWwWrz(:^Bn%g'P/˒4sBOJ-"g93jE[z
o4
oi
g==2!J^r#Q.(.`] H)&
$2&rO& ́˭V	]>1`x)
([<N[|y|&wD v*`q&~@M888?aZ_gLnZa&L&~_@y95)zP7R·Еݗ+MzAp=Amw,M1c@вjj-
䨖8yI3jw1pBI5g<vxscRȐv;gR^;wHsLS˩<*jُMTI4hQVS	?=/Z
163jg
V30RӬ6F\eյAߘl0Ԣ?rU!5L
y4Y>W]Ux爉mbywwJfbG>gnrQ!j"10N%:}G5+4dB9zқJt!ܗXV"=kxy5Wp^uˆ
eUkW7	J2&wUb"p»(.$GSW7=
;rf!B;oRJfWHQާ^<5.r-RHW2$n6F;?lؚə-hPq8Du֋;fSǦigRܙ}0BPc65}ƸZ ,-r.o5l}p]"e	P/$D0_q}Wa]=
JJُ|IXשdGeXJ`d!49>G5>_]_rt+{8M=RoҚ)\ӗpowWk6οR;+67?,=ӐM<Bxww!n-Tұ;}#aѬa90R-0BB_&kj}3Ok:0 >xp̓u&`HEǂGM
g c4R[.dF</4=m [56tGMp B-fhņv!,Ɉ6?BP.ޖX,º&9okZ2\@ģ5q128SjUs@3,ʼ,J-?=_.eJ1
݄?KFɒ#$kyJSH0j,wQ-`[+
5u.0w8zCRAQ[޾)HM ESZ@g7i^>`؀=rT2qpMv$p#LC<Yuأ;#N#OC&{feTh͜HxHn_ ".0tz,͊ј#(;9¾͚Ag,ZiL=[TuxtZYJnwdCQ;zUӫpHV
cD^U᜗ah%$f}qa>Ǆ 0/:# #jPx 9_'p?Y~\AR'ß9gO;KH	0Icu9qibmC[{#Q\O=z+_ΣL(5,[qifCICFU[YH  EAk
)AϷQ+XUGg6[ះ2#~V3t
''\xgh_RW79tу!)T
K	:©	6<vodB<iA&\cTF
eBԸz%kDCl_U0J|e8h\U"bIaAd<OǗUe|E/ǌ6Xzе+OFfp|&#̄..`jޮg\f;b)rd[Sk.>I{NH]-
ܝ&ZsA!4#D\yt!;6"8ں*Σ9ᚚ޼fm.VQ@ ":؃w 5pk$r	EW*Xt.W~c/(I a>+]tm+oU7Fv&!'lݱVh䚿
 3tIqIo\fIC$+LXK*OrxؤčԐ~7p*ShB\JkU^ױ
xR!ю(W|V.&I6cHPQzeFp(-̜C8ҵ"[e
Ln
8Oӻ5DFeEmZE-lk(d8Z\+(N"Ai\·@g}nU/T7jvAMgYXFj7x)3yO&ԍȒFГ[.[z_wG\g1Oi\tʋEww`tAr]^?trXrtfɢ;2MAg8#ڧiͫ]i59wtN?0~:0
Fi׍˽nҽL'r,'ݼeȁ8.߁-wjZ eQKb,%IQɚgQ5ҙ&c:(WH܀Qkp۳d@8Ry7;ɉK+"`B@Jv)U={٦MYa.EZ/e/_RE%yFuhcyL8 wcAB4%͆艖|hDz~%r+3[{<\dIh瓉.NO)g32:f6B97\oE:FM7ʜv**ޙVս^XגDh(LD/5/$y+q7Պ.(\ "BII4hh8֨h҅r \}wYGRX*k(__20^pZ}2@.Ε(:oo8SB US!2Z{| $m)?0;U\0@ٽeȪ(j@"~/ZQ߽	M51*B6cHb"(f=`lM)IGTbq^E).DNpnQHug)~JC	 {瑹GJTpڎƫ^"?$Vd."+i[%8$z|sĈQK3K)T)n"%2Tjp30ȠvT
ѭݪҊg{oWkt.dlJ%*BX
9*қ
'>ݫ71%%[ 3<3,FB{;sʲ6"Ujҷ쉤Y(hRijck0[;佺%6MJSxnX7NL53
H% 0m%N[A¢Jңa _*2g4Nhq7|uIie_֛l/ysc(+$Z#S6a3{5tcC?u˓0{^ll Ur]2n!.u႔eZ3p^Oavuf[yA|N  $]IXG.Ҡ|55a\UNR4Ṁ7W2|ujK}t+wMXN腌
6,=M)r_ 7	x@F&;tl,VAm;4
yAp7/	+RFSqߙg5*@a ejm#}7(*%pg*uT14]	qVXjhX(D~GV:q2q8ڨ~a%4A\&pDzJ/m<1ުi|Їxzs +QMD>봊旗ӌ#㊒RNk"5R (5bYWU)(ϳ5mfEh(3,ÆY\"Ӓ^9r1LF ,qg8.FrNf9,7<,C@p2tr4twg$$A?\RɤMjpbEG2
OȘBJq7t'F&%FZ`v;HUzJ~"d2hzL];zKqtk<@Ԡ);Q[&C.W#9j\x NAnSה΁'=9cq"]'34vE+ӋfM:1tS eG%Ɛ\4mAW5NBvPL\\mt2?/VK-eVZB0`+?l]JF&dERY!<'Db=iqL5d+dupHq2z݉!`{|1xRSE4t}:Ǜŋ8QK ;d+IU2-adF2D
hb)3Ğqio?&T 灞W} eNlvli_ nvRamow[?Ƨo4UG 	(E^F_NVK^UMe|/sr2;$Kb29;yQ3V9Us!DvҶ+L$w*l&ҚCv7erH^8kYj <+1#W?[|OT2\أо,=(pP#X)6]ZIxNr8ᨿ
d,a%IgI8̾[;8σ򌕤YԁUg
ꎫ>qZ
/#\5BZa.:OϽʫ&HȵTڲ&

c2c0b!%Vh,##,B7'Os$\(;~(DI<K ARkR&nzJ'n}/w/PB\)4LQgBSí Sk*@ޕoGn*_(Ȧv)wǘj	e:_9f*xU)oJ\h|淪Jyu}~@=Y[CS`>ba/F4$'gfq~<_!wy,@&o%6k9l(oS^L?LESnrJ3:јvjrp\ `YGL^;{0ν/`o{^	@w8lgmeFlbYY9@͠ZU_KM5%p)f_yJ]䩐ʉ
VԽ_g. g;
_2}Nf+m@Ơ+VQ̭+UDI.U%SQ[_8ֈ>
@Ŋҵ,U`>.kuڡZm,hړfB.b.PJv̦)h2cCvA}ZDZӔFCLx,̬`vy˭@m63J>Q[4}qQ'D:]EbrtYY+ K4c1$z='v,<-ܶRN+
]1s3'p5нdIPv#Lo~MRq	 '@eO"mD	" U%	wz XQr"_r"$W2NvmN6r
9ݼCs mg|"/%7y?gTߜ5:`Cbˬړ辿:${Edp _Li+Afm.5ܕGVq;-[5{R2=Bd4p)8Xs
mnrHcDn.WZ&uGiS8x*ߕPJ*'3QBcF4<LڻnJBkrUI#.ς:׭oefܯTGNWqF?z*֊[6Ըъ ?b7/D׽rOA817R:?l5_|&Wxq}VnMMaCbbBp*7T'FJ$Az/vTERGd(?$=Sȣ'o `A?L&_:{(֚X(b\_tzkw{Q*37Q)+TXxqO4A׈W)eh5<Hr6+4
XmYQT:t{>u6OuGViYu| CC _
ӈ6^l[13sϣp
yz
q"CExHZ&Uڜ+oԣG`E[V}e5-PhJikl>i"݋0Ur
:z0%i1O6 g1d7`[׶~p˭ՙ[+"9 D\Ėݙ3vtp`%ί8?P"_Q.[0fwoh(0kN׌Rj!:At4+=r5a1Hm;	҇Z2{;9
PxoXA';vzN7zv~ӹ`M J[K9|O;Uh@.ءiB<|h2̭62gIPTfy~0gx-&^.JoXSjp6f-n͂J/JQ7HVSCg0*A*mq3bX3jT@	BpJXLg8wߑ"cSxQlp${i},5$wV^AWTI(Ϋ%nL^AAΆYTqP[Hߖ9[J%;U
TimPOKhw^KE&bgWG=f)AHKr:$KJNX$o.	IY-ni
%	LG_).؂5FHa*'$%DHP,ϴ-뇣XeYqib<O`Rp}Oy'wUFYxA{Xd"#N1fR*e_\۞eI`<燩E5H(*<oC'dFl5- Zq2o)z$
 St`$4iP[K(v.|'qow(i^rYx8+i+>(%#.* '*%kH
\cJ?FYZHrRePLP{Al-Q?k0po< 	2'H612[4j
vǝp<Me/r[e2w`,Gc
^%!b;]qJg|NoH\Gj0~jÂ1V#qύKugĚќbXP-~r4]!_ƣ}k|-$j_$'8f##)nV!04Rq/Ӧr:im%EGq%ݵ2
#̧A=.tIME00&	LD'	7ݚ
h.$1b8iŎGYSwWqAy]Ih!?J"SBP+cT}:K2hp]p_`
\G)8@1+{ܟ'8w~|EiYBp@
蚒paHW 0gĖ/074"1ז"Ի5&uWb<	W6Y˶GU<*3GO:u{. s6A\ᨫܯJJ!>)^ʔ}k)
*N_>oJXKetQhCZ)#eY@2XBs/B9 d,!??X[ao`0tE:W2Z;be"{{sl-Ϛ+R0	?Q婤8f{	L
6(wnMlJ=z|3xiv>kx 
Dޡ`-HwvPVz]t&X07갦̈-+]y{kڑ{ ݱP͙Ԙyr&	9 
6[ ]5V6h8q\
J@﷢,y5XSgf[9o{#T'e㽌gɿ(|cs1f ˣ
n[!ygU@L.5Kn,FBn4i qQBBafcp\݆Lv1&}\QgW+5y!&C|mJhL-ԣXJLCz9.*h(GZ-jc-ܽ^ܝS +YED$(`,2vS+xPz)NG^A=T+c	 Z!7;4a=i	43nE"Lm
Eq:g}AP̒hqoRo=SE
dl/^y~ȫ\a 
>"xz8vw,a#I6!əNwfHՐ+l]˝],r78π
,XQ=3eky͜Azl-8[֔+)A[l[eِDjuQ"ut9
kWSJb#4Go@Vlnv=շ2 _9QLQ~2`-&ģb.OX\φQju#6dc(jTe4-1Qb(akLeu:e}0yM4,D=@tA[F`aM	؏ycRNU1
Cf.A߃QSj=[KȴP}':lcŧ? l;?P
\{I^o/z=oW7/^
}MiVDn:D9|	~\'5!<
	͟M0pSOrT2=@<:pdUBn"p&$5';	J2kg`ʣTاM1dcڝE>)RH+L̺DW9K
|Ss&(:2,(5A(#93nn&jU.ocK

}PC[5Αr*8hHK/xLKgERsmR0?qEybeSn^+W
߬ƿjɼx4Cu}nf=!&@1> 
e͠瑮):K𒉤3C0e#i阌IZv.H܍:kGSHIBv{f\!؋qg)wf;F.˝X3wrK7QtFm86QJQ!YS׷$@oBwn	b;nBu"}hE\({sZ2}yƏ)>_ڂ)%#+Gcx@5n̖Q
nQЌ-6,i4$ȅ1C̋R61?h:cVSkV}w-	0PH}2Ym>#+{Z8YalsL'!"(s2&ƍPCxc1/6bd5[c:6uDxǪY$bpmo1!Uqxr0novy_3f=-rHLEhmV18Oe;Rg%]@,63p_*fGm;ȡ%s+e]܉+_L}vC_}WLR+^Գm47i!5etEKd=n8ԼLʋBhȋg`DDNKl~&wkG ;Xu9f^ɭ
yN_7,Yz˧e߳-":Sec"WJ"H47z
ŭČk-5&K7Ǝ'R=ϥ0<er`иܜ4Ng3TUuFۦlYO:j-w/	Q|EE<&3b9Y܆cڧ=|iO
wRgؗg$/݌OgwO:fd@Aoe	
262z皉(W%@T_Đ*!s;ZPB Me6ln[3P`a P̴}Yjz6pE(v3sq]2EkvqLT.IٹSV:Z·]^c){вwѥMGV"m 
ގPnY%Y$jd^8XX^8#eY@(.g'N2CaN)zW*B/y
377-4" oOhURc6	W#y;{fyїGH@!9.sw
P8+J^ WkU'=~A(Pz$*H
*8e+ќA}tn;r*"Pq{NUt_,DC̤9])-QgLU1
I\ɜ"ާ. {+{fF9Ga rP''h
AFNwZv94;ΑZ~m9U
ۦqTy<-P Yٝ!ff?dG_<)szc&c~,3Gbt&4)
(B(q2?C^9 &1i$!Տ+aL|8Y~w;nMI;\0=QM2i^,
lwCE}LgvaE%}lȭ5G,.[N	kR$p	e	@8tqǄ)бP-21fMAde?WNh83 xՑwqc!*mepI\̥6=%GhXmv?jgGӉZOgz>}Qv|\[Pk FeCGIWM뷿N~ۗ?~?/Iu#dKyX=ZͬD!G$n  bg
`ΞSIz	%cHl{nS? !tmGdiSI{\ tbp?xw/5bK+i8}1Ґ7>T|Kwc݄*Wވd
P-(d
Hv&0"6;X!_m1UK7_Da)Ԙh-.qz-<&8g"tҋ>4<@WD!uH*/M'L$P,hܹ=W궉CD%Ͳ'	bXi_Dm5]ν2նfˍZ7W^.ԠЗm׶LKۯ߾z7SÊW߶\5#`:>$[kA]Em'5*?,ZS@_2*Ue$)z6svk؈ܘ߹VsAMYq敐w4FO)Y6(wBR1|>hqX뗛鋛WW r2rl²-O-By?\^ʌV^l6[/19V	 f`o"w2>nknnB>گ-0yytgYQZH1 [M{)ŀ3j'vhPñ	펹xZ8*ٺl;YӕXQ;;}H-7u^oğyL
E!6Q:ۼA\´4<
iC0$Sk׷ZA&+PA2<78.]+˄$6鐥2J']$ID4{U~Czõƭ%~bֈrFY3S]|9;Mb4Q^Cz.7)KڍE.ZH@J6\py`0H:aK`dT&ih#T(xG 5q;Pr@ES)i:MQsU7IF8B`@ `&RV
VeN\'*Cޭ2XF_J!!*c%eƫ׸'S`Hw|	AI_?KZxYâMPʽˠ[e3O>G/-Z+]oTM!%B
φR#<}}fy=Ysݶ6Kl08n(]Gj݅;Y]Z~h`goΛ7X%Rء,$43S*&\Dj'Y%ݲn"l8F֮d2+[qݵOK"tLi! Sܟj9Wt$Y$^Ѽ`	c8h@Bd8d;G}7#%B*'8!AL(L]t%P6)PJ'/Z0^X(j}ÊIRhꡨO`g,XO@reeU*h=^,ȶ 鲉Ag [~yg^n;=oӻtՈft[hhp_zJ3؃{oɮLbA2+tȞW8K>bR?Xdh.zrJL`luDпO^rU۩lyCS`ΐk_8mLDǲ.[<O9A$|PpޔJ;45ayAvd*l~=e>ݰg".σθN/W{`$:WzuWWz/R;42RO}^	fIO>'ĺ#7	$ґMAM4*7LS	;AHt
N5Lod
#Y	WlU^/g0ٝ3ڙWH=R ύV)E^)(
#0XpB]
i#WC^ٶ}B(Sm_]s/YF,6:!2wD{e~_2S7;oi v(YAmSy%.40V:,)KPd; puڗ65W}þ[L$EhQr
c'87@ɾCTzrO**lTCY9 ${ҽEC/`@&<`KTx5 n3{!,Ep.2dz8Y˻ZwSieJtT?3SdN{t	FKmRqu2ObZl%)Jʕu |}1NO/n~ KQb@k)T`2Z[	4[Έ9?o
hbNOt>we8g;yUi FMB؍o^
1I
MSB']iXmO/tB [nL\dѰW~9{@LibPzJYp
007k6^sa\wj};;W#'q6%6#1'	-IxEpk	3 fѦdtlA<=dE+WROДGˏD}iQ+iuo\_C6~]Vw8>}>C=F+C-
08uJr{"AY2^	kH3,nMҦIC\F05qF]77ڶ
sd#t8*5c<WW7(ջ_M_ۛ/~yzF	$|a	>2U+rBY! L!FyO/AdP|t*KJ0Jni슦C!%U1U7Ө)\'XH䓩ز$\]QY& 15"t)RHʿjt;&#V+_E-,`[
97q&XJvT*X蟕n06ļ{\TUϜ]Z2
riNR *aoTw	 o'*;S],)J3k	C>>lWJ-ѺR}!BUR#ʥ2/dJei*z}PZFsWUBTZi/4r,obI`YgUW4PZ;2l~Ce0\){Iߍs$Hi\p*4DaG}T)<5jVsoޮ<X`s6#sʉ˯91b{ӻ?d<fk۰ ѷ9
t*}-MHˈaãF#ƟⰢ&PBN[h'F&phj1p:<+rl4%n GB&{,nڊ%FRF?:/4r$+Ab1qٞ_V浐	T 4abӆ祡%N#~	^ Xf9on?OȄ|~F&c|F>):17dAy_;Ubr|$el=ՌGdD4plhY:,Џ%Sd':UkE3(8*2ܽOy%%at'QAĨݷD%$<ߘ[4(qy`$YR<-]S%57"!iQ+]JSy )!cUIM&q|AٗHiX\Vq29LC-%¶'L^x|]Tt"$MXbƍsjIEE=4JV@8d$AW#P$x >o#~Q7_.<@]A?6t {1;M~iw;[ﲝL|zrG,
<!a)e6@V~#7=9 )&Z,wZwʢ?fݦ!*-L2zf|#[9F
~'"z8 랶Î|&ML|^JZܽv~}=`U^Pg@q63'r,9i?=%ݘ;|DjgBv9[?dGȌǁ3->pv8
:jTrT-/:2ؤxF{CCF{n)8.ه~OX}ޡ-e_ZҐ$wJUP-ݥEY2bNBbLs
ؼ4uB= 99}7ya
'>[)|]zt؝vj:#}v$Υ+_<s9a!)nu~'BLT5+c:-vtĐ7PgK'Oc{w|7 pq31MKq},t^ z-(zwx |kmH/߽zwr9It@4Wr-paZ}-,lۂ9"o)Ŗȣ#'&!U˓䀡mtJ]۵$fgplӷhTGݏ]`Ȝx.ߔ?qᑻ*Oz7
mA<0cd#@sç;r4¢їh #"FR֗2X5tPږ@}#]>'R>ٚ

1pu}&:X
a ]QFg],/}߯s|,7le44˄:-p,w7NZ!	^A|
Ojf%hQmEgW/~Ȝ`\Nu$xߑ1e
(2ȲT.HP$l폵@N*qXuG&k9tN(rͫw* \lGįZ>dJé\L-c#f'[7%ۣzMjD  ~/43lm,wl4;tZkܐ
vԃWp/VtHc,IY#tW}-ns&rKv%"S$utK!ERcYUB&q,F!սs>>|-2gٹ6Mn%<˂q}aaSAb@A;d(~q-̥R){+]Csz'R[So-B
gߦv7kiy,ֻt/ң)jAzS#Cm5(]hb`צWdDj
6#CTԝn ի)ƹl{_5f:Mp2p׋d붶"Y>15S= SO,Rw֡R~/8q5Q=ɾ.BO'<X]5N|K4x.wʽ΋o)aܪ^;9cQzLF;'?u_wԍv ~x#M#shdeL۱d"̫LRFa+"}Uo*Ntq*禴6ЧjrE-~Z
O=J*Ղ9pZ@3t]ZQjTxqsC5"fX-LnoK^f+TLq	+(__]{a:4pulΩw/zǒ,Z涐^ǳ$4Y{/_Zi9Wb4JIc<2XpD.H`ծkj
r۵Bg<tA#rS*p*d#YnD➼GR$3YBvœU.7304:$k\犯cҗcن.׃x]﷠DKb)O/ٳlbi
7n?V)xI!tzpeӻtũ'51Vx~q
<&]ί:0S$U7H?/7ٙw1m3.y{
<+^girWZLOiK_?+4Xclʰy´\	oJ+Cl?uhSR_nvHRK+ݨ"Ka!D&ņ88C?g]yv/:0*"g.;Yb>a}|fJ]ܴ!  -_Gc2ӳ,LN0.'(ZA
F	 +*F~26k~Y]mjm[!csco	/ۙvJu!/2ı?B35^
H\xmu
5M+8jbz
3W.U3V X@jDEES&%Ww 5Yt\q\ӈrv;/ /\a{
Vko&K2$+cqGQ01NRVic!!1Cm<?Yy|c/H60Tk/yߵ%b[pi,!uU8(,tQ	]} F~E@T&pͳdQ:'5QRIpM,{)}wRu6Vvw iwmP5[S/e;)%anΣpSY[(Υr~_EH`/R(qlZ5?,1ȫуOQsFmŇxҥ2L+.k H[k=,U.ޛ:)y.
HF-0~^5)㶚^Z9lUr';zFxWV)m]bj!s[y*E!51Z;Em^NKJ|;6B/]l2<-xqۮ65ܟpNbCo=.AR~Qggmr|5INj01{Lm6K_k2ỒfQ*().:7v)1u(i"	J펜	>I/~fҍ̯o+'쇯`a9'4NJZPWQSzJ_SDο,HIfɹ9xGM5dP*&ϯ^>ӳbŉpI,tɜgVgbc)G`L
vFLկܚxI0w7Wg26!svUQP;f+x&$۱EyYJ->`% 7/C'USw[is0OP#vqZR[<d߽0u˟ҬӥL8[=٣2[!7~
5i  'wI.'sCCcg*36GEw)h>=sE<}ڎ&y3nYl?YǋFXZ$BƉ4V,YEon>"ZͰn}rK$o*zsQ*j֓nܽ2
^Sɘ%P4ӗ;·o]{_)zE%zJ 	_@m̲fpT|pµLB	dq}!@䕶8IVy18ʀZ:9*YFnX:j;=$3!ȀB Eif "zǠ""_PD4L6W,4<%IwGNQaR9+g;+!	"1,/lL/kDZza+`,'ցUh%裧I~:?+uaOnUS]/۟qKGOcC@T/i3jOp+	7lŒ &P{^>c/f+M(ЈKX\aqGrS
dП/偫⌙ݪ, Ao[3tdNָ"LYt1z^bnTX _sV>"p('GFu,kE|F\8-bq23"v茊P](__9G)]D6n4Q4a
;<BT0
+ <*uù[^$"MK0szU/GWӽܠOH2hyW^V÷K
&9x.pofm>QWh76M9 B:g]JeqVy/Ǜ_CoB#-ZQ"°_HMS)4.H#xz8 ljI8zaf/.*|>,R5X2gҮ
;n
J;DPrQ;9HVE<5T>碂ܮN@YDaID2;Vt?߯~-eYH)O0
pE--{~m!rєߝgI瘰NH-Oui@Qxt*OY<"	< !T; <ܓ#a+ue&Gْ-|	Ff*ޔg3*+͟/6ƵHAM
ݻNJ	 5\wzp;>sG8>ƾ9kM$fJTJs.7
UVf4q/l}Q<	D9Ry?F(p$bK@nIuayUUd>:X<Dm@ׁ1RˁkTXPFt{mQ)
=;(=3rbA/Xu"M&SV]tjuFxZM?
bː͓P4]
FNT&bȥKqpKa^hmM?4#RR|?/-0xSmp6Uy/}}J)GZ
a>
e8»;aps `F`ںG7l, ɋnHo;m#x{+=a\9b2*Q}f`~-qJm1HP-79*J])"x4yKm!NF!⣘\tY`sTRXxf֗%^=J
_ye܋Nooנ^A^Y]D-HMɡz
NqLKǯuw^)fԔ*sg#:	3)yGFY||gCߡ+	QH	u`qL-ϦG6}%olܔQ$rƕ$ڍ,JiK4,d=5m[{,%T'&L<jDN%foM;[("eg>B.^1v
-|::I(5pˊߓb"v	c7#yAWryRZ_JP1M4j٤0;KƘ<1MU]2.hyE9.U>yl?)o7"qvc9AZA 0˂!5%s/l棠m¯WBؠĺ;_ V^h D"ЄCCveo0],& ؐ,T̵u{?цrAKW"+#3M
wz~XS@g^xRfddUt9ئO`\~7Ip(a}$̱w}1z)J <XP_̾`5ѡSH8X%=5t_XE(;fB cmh{WSv?QZ[PЄ[3>]R%qV(EFDCŰJRt	@ʖU?7޿Y*ΐvk7C}:UOƸ4}S1sAP"
Tx[^%gJ14B@bo*}첗9	jX>ސܹa_tW[4<2ܷm̊ˣU~gLƠ9xLLnJH
f;J>cZgǺBys>8@Alx6 ,$Kavgpǻ1tJBG8^NLPrtM#DCGJ*a*9#&62@MmH|H!6fت 4c͠,W{BQ~
1*ˆ`o_Iݬ5~1XtL
Pqm2T@L3GfZ",=lJ2c!Me-ߺaFV]3~#\!)̆p܆do~nyMns7Ftυa|Jh^N2^VB$\g/!wOݲwO;9wvZRa`NFLK	YŞ̞Q΍ϞwyFH|!y3g!h>0ս;iݧ|XUUe)cIY}X38$'8u)f@\_nLp&tOQgMK[h6OYqBp̾vOd5>h4XݢTR(
Ł7Q']}8m8
'ۉB$
~Yg[Yq$ճ1Q҈HoKwfm7jz<"GRWR,T.& d6Dft27nrNC|e/`ix)SWτ8g18ڹӣHӗBV
T6"Jy荋#+	Yl}fa1¹3IuWy{[V@o:9_,ιAQIOF`Ѭ'b	x/tKj
띷6&sOV#_Ꙅ|	Bu<,\vqƞnDaVxM<JqT̨uGXjKJ=42m~h)/#J23bpoβbTdR1y9{MIԔ@\xǐ졍@8I_Uih! ⤅z^zߺk"?h 9T}w֜3J&9%*WS;t{D9ǣ4۶5G:w䁉bޚ_CɌJ~ #b6CÅt0qB?iKD!Ea<]I~JEv;A<N<͚hJ^vP(6ZWt\mQǹf<\45tė}s!׸xJ\?8)>3l֚G=FS*3ZRt'sG+NNus?k^CTj6ESOI~THiL/Gƶ2R].!PITϚoޜݥL@CO%[-!7@yʸLWWD\PYi
ڤ4Wܓ>	otf+Z|_XS,lhfW	u'SҴ̸n&8 Z޺حU$WR&n_R<nPS-ħ\A~3m|48+0ۼ]ISa5vö:Zy#M|I(iVc6%-iMջּ&qIWy؎ܫ84Xŕo:.}aY1,₀R!o X|/؁\WyZ&ڴtÂZ>lg Zt]-c^Iu-gY[FH#
O>I">횮jbrqC\[j|osEUV$PN::O)~S1٠ݦwel\YzCzC  <j
)e3M<Ni篜75ӺYv.lex>dsv+Q}ò,3ҷ~HֻV-Eʎ9+j C}}itG#+Dsd=,#Ghp'2^k@2;'+S:i|'=/9>Nq&<s	 
Jr(v:P2Ag[{R;K+Զ1m$`B8Dm7C^u@} =h[hV}=31~8DOY?GUе}}.tɽ{xZmo_8`IhXA-y}$߄c,|BɴԢݶIU	:$9|4Lvg9[QzR4i֯XFbXbB"lSNFhxM@(Wx3쁸H3 m%Rbw x7KLɯ֐!k6E%ωi^wdw-\ZB*N'iQkp	#w!]
Z t5N,<)pJ0H^&"r4Xf AqpQN$Kv
/8KJJ\BaTmv5l+&]<Gqbr#
(D$^Z-$C,$wUMd1`t'nb|KHsًfB++{Q3}! 7*Nn_T쓊D0g=G봇l'Ff7p1zklf'M+Xr$Ҡ&W3p#q9s)2*xH~X0s^"o(}\)jK5Frh
ߤ'p-X`0~FJFth.rObgq!efr|
.fSkD(D9RFbŕ`3؃ñ$w$}v
أ]jjJuC0E4W~u](aM+i
l? S24%I9/~2ԃ8OB0K^#|/,XT?Y0/Љa3(sZLřiL;-)k
+,Ol
TF&̩UiOffq\;rn,OB|! =~	odfD/kQEț\șܵQ&+nC$xj~%yKr{Hm}3s^8N1PկЛSKz6eZDbJ^O-DdK뫐`H/rW#76:%cH9!٬6ထ8É,MJ/
u%0~Io"n" *[	R^Rʀ%%y?AZnt*ՊW`ڍrF
k'V)i^oҵMs(&G@xq#>.\-ϚюePLؑq$wA<(##mW(X5)z
!G#	J'QX[DGeܻ'g (-Æc>΃q4lGloo}
8Wake44
)>B{=Fd
0HgkFuwx!V==%m{`&/IXEqu)Wku]<X6RDk82UNdh%á͊!cuzP-A|!e	"|pPढS|%vW\	 Rc9+g5|uu]
0W: ^mtavm(?2zz(f|Rt@~.r!{;F2+=Ɏ
)0>,[?)Fnr@yU!M[^2+0LP5M,U3VS@*t8 jYKʽ>~jh1Lݨ=ע,V_qL-9ifߔS?oxe$?$契_rrSk<etfɿ8j*Adk&/٤QQjnpSE:P Ķv!Rh
&6>
nRVٓkH2r}hӑ&GwATm=9Y")a-r~?è$!t[ϜN]W UYMK]n!|CxΤ`Mۅ%3
0*snL>iLQpj4JX p
qGD΅[_Dj!e4+, BWDム,m8ۏ0x,﴿GO(A>lS4N?k8É	:$}d¹~_93|?MT>ϹS	S4_~pyjѮ{{GC8E)y:SG`=HM156
ޭTi^i)F{H
-%ɣ2g6-չZf-s'sp#'4Ѳ`tἯDj&g[k'
`ejaKzw_3 &89,QN5BJAXUr*Xb>fZ5V@6){ԐT /_PS+'J=tzTò;,T: I;8':[W3uHE?1R LA;.7WR(7ܰtzhr9cf@K13QZ茊`唭&Duqxqv*RcCrT3q%+Jϥ]H|	9U*7*lK
OU=ZD=qQ;DY re`7/RhݚI\S$M`IY6M=abf-q
3(0FieFk9
wsǤn XތE-Z:FJFթېW&^DsV#YIㄨH?	Go%iCQϥẈCgL\X.>%̖pJq}6	z5qo$p3.@b	"2Zuxg,YMt]O/wLHϢ/d {5W&mgYNM1"҆ T`jqI
);׈d\h[-h
I)r]2έQPy^ 8Q^zW{4~PPk9n_/O+`%jmtRbiǽ=׷IiR<D^L`'<a<`
,N/bxHÚ[lr@qW-ACw*	hzmʸ|$;cfn,CW!mM!Қag~jdmc=(Tb t0YD1:4T6^ӐtA.}}ՏQ_,	o+QB<]MiMqU/|ZruW&:Z']Z T?f$UI)!gZyīޓZp.q.v{ٮjq`v#!wTGKb1͝[MS{`'JO3
j0Ji2W0]):
	@{#A"ԞpɭbTcEr-?OQ!YINTeG'Ӄ{ަjy<9D0Hn;v>26RmLEp.=5mMCv7E- Dv]^<=
hХtؖN<Yr5Ii=dv\fBR`y`Bp=3N܅Pbm/dF-5\CARL7p31|GR*Kz"wyGo- U2[Oc|W2}El&xb8唠R0:5*Okl9o[w5;4E}{r1,7{ 
eXG)ڊl*fl'2%NܸT?^-,d'

h_'{u7q砖/E#0ZҾM%6ĕY0XH}PvLER|aݲ޺TPOQǬUHMхXpup^;[yBWN)\055ۄH (sNDT
1	E&ғ(ᇢ&/9:lvvb+4y.櫌ߩR`uN@wEQ5@Sxal' =~(+DVJ (F±!AS
4< ֟Z5T@S9	1̥$L-q
]WbZχj@.li83]0u~hH9/uq*xQ4`6ik`T7LvuDi^`AƮ|Y%_Y2_͒WjaCZK F4GF)<>-CI#p0!U\:ȼs
o4m'A4;
CU,	KΛ-Uܓ_5O_;Q1E
P-z}^ҮLT L5=z8N8زתA@W7c\0u~ʧdM-HpOPRJ2v2G>=MANkutMTvrZT%yn >-*$ge4{P6l=il,Юg-p!#PPJHF%aa,Q^¨>"ǊpRb*]DP.0XljmZNuMx3[[8_Ů́W&q-+}B!">QbﱚMB/zRjv"1݊;4$ȻdبN^?1@yZ~j%ұYysm	[vmZ&8gsIL$*)"gCR[|oNg<BR9ܒҫCjʇ*2Q
ƀzDrFx°K@ʉ#wLɊo)t]l3,(!̃6{ɔi'c[+`B3"|H%;fupPc{7m@{d'7^آJ|1(+KeudY)
as$,Hy[%hv;U\:!^whaveC͚`M4Yqϰ_ &Y5Gi|s']-uZe0ohJtv-}
Lcyb^=! kKe'>,ߵmBSN	v0r~n^~p"%
D6Րu<=#S@+z$_8E~T<śIcJ}`^Hy'(n,卷RsW6K[솞B\).$w7V:b R5.G[7^%<s/$[\*3&7R`I'd{MkaOGFq2u
~iˊ'vHet57-Wŭ"t;AKD\{k)蚞Ɛ:ugʨuO#duA!|Zf
P FK=z[7Cx:K2Pg$BmMeoIRLHox抸uΣVZ_RnV8Ě^*Ұ]jCXcїk)6.@v<]V)q3g]]?_ahՏEzA*h^i6z7%Sy$1U?܄v&tytJqqހ'9$#НHq\2\Ў`ވrEח:[	/
dK1㮼)1M{	BK&iJ7	jB%>ݥFm y#'+p.l2w^ i됬99w3j{֨5i/~`ۤnab3ٮ[Bmcb 4͐uwoX\a`MJY9K¿:tu(=ݕ˝mL+ާ9B5
õMnG,V@Kw"o]fQS}Y<WsЖj&ݞ ;<rqAx\$2I([2HSa)Ek.;Kjfkn:EDNc9}h#"(cDݳwT)./p9	d&t%lYσev?Q8^(J$o\/6-kgIBG
>au 6Rl
TuZʭ
XrXqR.
aYCzPqKRrq
$٦w_47Ώc-[!Q
<>[IQY%a~J3)! AͅvhTX8L*(L`R;)RQ9nC)jv7ShBkzE$eU@`@g-ͺ ;p-9Mm
\cb o
rYQR,R/-d0j#`,S2$Py^+mvn]:˖{{Q"W
a'kMD5\Vm$(qP/쟒4{MG6Eo-Ojڛn!Ix	.AͰ!J9iعfG6V!zlims9 FI:p'Q0qӬz/o?0XcH?a7.:WZdɰ> Ijwq&s 
՝,NB}NߙeS7]p:s|%[5Z;dJbs"C9I)EueÓ	f:ƒ]7P]RiTV0$l)zQ4amC!2!sG~/!4'e(M`zi"/mפdsXm ~b}
˔I5d~:U
J`<|{VQu8)8DVFN<SlˎCp,)<Ho8tV)a<T#D3^NTsG7 ƞZC	DJ	UF`SE|I.CfPMHteA_l.<qXAXgUUE(Si$9rO'Ӡb"#(D'w㛷dxW]7O*ŔW2Hܜ}peuڇ?+Tu\bC+TpTq1g(_>t[ZwQ}nV dǔVg.B)5U^2gј\/<mͰ_.:+^D%v{8ּ}3.Ŵ aCwK]!6H{pax(ei׬T7`a<;KJ>)@Y)&n
D#1/,q/qu1s@.4gfY&_%.@TAn)+'Ƴ]	O_wsÞҽ1(N=3΀-9s1Ae`eC̘S&u]r$Hht1x xF_{O;ה'2.JϽ_wQ  +XFiH<q7Mq*rU^Z|+k$ɘL7z*;KW͸LKHK9%d&I?dLUD+Yq ɫ Ԫad70o}L{*Yx֖?ǁ]zkwFY4>h~䇺9GՀg@̵[MIϭC3|4MԌbtz0R㬔\)ˢ:
.wӎ5l	BR;I{"V<:qC!;}1HcHG#M0BG+uLjQ,L3\Ȓ.%=c
i[tt
O Ym2͆\Vh
ɏ6F)wmqӖtO#sQ(Tz3i?mQFnÒs<mG儼"De;2*8Ƞ4GfYʁmԻ̥K>	>{b8 )5&}F=X>t}4M˕0n2#s9Xssi?^8itȱ H}+k9
A~PY؎@3T8G4ZL\9&r3:/+]%)_$`w}uqUUU+PfFқ]-탕KTM2Dxj.l'L~9^Ѽja|;N̰V`XQC?Jpb>u~*
{yLԓu
F12~vJ"sH	Q@N\ZUG)їuFi~lrTf}KΥ,`KΤ/8ay#19&FF5>$ZD
ŋ{+GqoH[	ڋ =\u1B/e
"0ʲo3D+Lx@ZA?n9_5^S1N;fq(}mPh	R5f2+XxBRf?D9WQl"Y~w%n,-g=rc8aKfeeQІ#ʈpYQWx	.E ǿ{vX]lRs7_?
GZ6f#m
:(_^PMP#Ӷl"Eo1HɘNݦ&.U(딍l$'*

~3?ѫV:-Tb)kK(E]$@?PUu%Z$Rm1ԗ2C 6
ĺd'+)IUkNⲿ-Sf{h6.n=>OF8O?Zz^M<)sU00_=Z@VW?*MWLf%w<.~~+p
DuOKmwOoYgq Ce5z*GGv8f,`mᨏC!4ok*X9`^dj, 81<ЀRC]V[
=*y2樜T4CF2
"'sB}tdr9:Ja֤*a<(H펲w%*Yr EWqbC!	#q5D~j5
iΧhKΡI]K$k&gn\[PP^P,sZ%ysƨ
J$i͇#Yx,bl+Wd,ǨinxLy[%1Wad*Sm6;cq_sqq:@*$MSwܡOMEr>, ] ,!9QzF~弆m?;3~zXj[g<u[Id>=Px~b,4sVý#͛<d-QEofV5|Rxo5lfȥ&prH(En޲@xz̅=f/)A<aoo} 芾'ŕ=V7va;!lI۪tyӷxmkE.#. \{D|C_#5]	huEIL|V-ys%*%	`hfJ~NٮY+~HP}g2LDH['2g#׭ň#?؃,ZRQ77/7\̆b
e.u0{|=I	iLaig\unfYqO>veM/Gw+iÓU#$I{觗l%5Zb^&F,KJ"%<}sǈ}`4W~KlZ|#b4ǈ%l1ݚNp;y
 N*r9VV><
(ka<=OGM'&#wM1rpb)Z#䀁h@NS<b+@QRcG֛^Ldҍ߉As,^H;F(tq*<aTӏ/vI^                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   